#python #sorting
#python #сортировка
Вопрос:
Я хотел бы отсортировать этот список dict по ключу списка, а затем по дате. Я пытаюсь отсортировать dicts по ‘label’ в соответствии с label_order, а затем по убыванию ‘date’.
label_order = [3, 4, 2, 1]
data = [
{'label': 1, 'data': 5, 'date': datetime(2018, 12, 31)},
{'label': 3, 'data': 2, 'date': datetime(2017, 12, 31)},
{'label': 3, 'data': 1, 'date': datetime(2018, 12, 31)},
{'label': 4, 'data': 3, 'date': datetime(2018, 12, 31)},
{'label': 4, 'data': 4, 'date': datetime(2018, 12, 25)},
]
После сортировки будет выглядеть так:
data = [
{'label': 3, 'data': 1, 'date': datetime(2018, 12, 31)},
{'label': 3, 'data': 2, 'date': datetime(2017, 12, 31)},
{'label': 4, 'data': 3, 'date': datetime(2018, 12, 31)},
{'label': 4, 'data': 4, 'date': datetime(2018, 12, 25)},
{'label': 1, 'data': 5, 'date': datetime(2018, 12, 31)},
]
Я пробовал лямбда-выражения и itemgetter, но мне трудно комбинировать правильные стратегии для ключа сортировки. Возможно, он просто пытается сделать слишком много за один раз.
Любая помощь или направление будут оценены.
Комментарии:
1. Подсказка:
label_order.index(item['label'])
возвращает индекс метки каждого элемента в этом списке, который соответствует порядку его сортировки.2. Давайте посмотрим, какая лямбда-формула ближе всего к ожидаемому результату
3. Я бы изменил
label_order
на словарь, который сопоставляет метку с ее позицией сортировки. Т. е. сначала идет 3, затем 4, так и должно быть{3:1, 4:2, 2:3, 1:4}
.
Ответ №1:
Более эффективный подход заключается в создании dict, который сопоставляет элементы в label_order
с индексами, чтобы вы могли использовать индексы в качестве ключей при выполнении сортировки:
keys = {n: i for i, n in enumerate(label_order)}
sorted(data, key=lambda d: (-keys[d['label']], d['date']), reverse=True)
Это возвращает:
[{'label': 3, 'data': 1, 'date': datetime(2018, 12, 31)},
{'label': 3, 'data': 2, 'date': datetime(2017, 12, 31)},
{'label': 4, 'data': 3, 'date': datetime(2018, 12, 31)},
{'label': 4, 'data': 4, 'date': datetime(2018, 12, 25)},
{'label': 1, 'data': 5, 'date': datetime(2018, 12, 31)}]
Ответ №2:
Немного сложно сортировать даты в обратном порядке. Вместо этого давайте используем отрицательное значение индекса метки, чтобы они были отсортированы в порядке убывания. Затем мы можем изменить сортировку и получить результаты в том порядке, в котором мы действительно хотим!
from datetime import datetime
label_order = [3, 4, 2, 1]
data = [
{'label': 1, 'data': 5, 'date': datetime(2018, 12, 31)},
{'label': 3, 'data': 2, 'date': datetime(2017, 12, 31)},
{'label': 3, 'data': 1, 'date': datetime(2018, 12, 31)},
{'label': 4, 'data': 3, 'date': datetime(2018, 12, 31)},
{'label': 4, 'data': 4, 'date': datetime(2018, 12, 25)},
]
def descending_sort_key(item):
return -label_order.index(item['label']), item['date']
data.sort(key=descending_sort_key, reverse=True)
Вуаля — нет математики даты или другого обмана.