Я пытаюсь отсортировать список, содержащий следующий объект по его атрибутам:
@dataclass
class Room():
house_num: int
room_num: int
view: str
Я понял, как сортировать по нескольким атрибутам с помощью следующей строки:
all_rooms.sort(key=lambda r: (r.house_num, r.room_num, r.view))
Но я хочу, чтобы пользователь мог указать порядок приоритета атрибутов в файле конфигурации. Например, если в конфигурационном файле указано, что приоритет должен отдаваться сначала виду, а затем номеру дома и последнему номеру комнаты, приведенная выше строка будет выглядеть так:
all_rooms.sort(key=lambda r: (r.view, r.house_num, r.room_num))
Но я не уверен, как этого добиться. Я не хочу, чтобы пользователю приходилось вручную изменять порядок внутри sort(). Текущий файл конфигурации, который у меня есть, представляет собой файл YAML и, вероятно, будет выглядеть так:
priority: [view, house_num, room_num]
Какие-либо предложения?
Вы можете использовать vars
следующим образом
from functools import partial
class Room:
def __init__(self, house_num, room_num, view):
self.house_num = house_num
self.room_num = room_num
self.view = view
def __str__(self):
return "{0.room_num} {0.house_num} {0.view}".format(self)
room1 = Room(3, 1, "a")
room2 = Room(2, 1, "b")
rooms = [room1, room2]
def sort_(r, priority):
vals = []
for p in priority:
vals.append(vars(r)[p])
return tuple(vals)
priority = ['view', 'house_num', 'room_num']
sorter = partial(sort_, priority=priority)
for room in sorted(rooms, key=sorter):
print(room)
Вместо использования lambda
вы можете создать функцию и использовать getattr
для получения значений атрибутов в предпочтительном порядке:
priority = ['view', 'house_num', 'room_num']
def evaluate(room):
values = [getattr(room, p) for p in priority]
return tuple(values)
all_rooms.sort(key=evaluate)
Здесь как нельзя лучше подходит operator.attrgetter:
from operator import attrgetter
priority = ['view', 'house_num', 'room_num']
all_rooms.sort(key=attrgetter(*priority))