Вопрос-Ответ

Sort a list by multiple attributes?

Сортировать список по нескольким атрибутам?

У меня есть список списков:

[[12, 'tall', 'blue', 1],
[2, 'short', 'red', 9],
[4, 'tall', 'blue', 13]]

Если бы я хотел выполнить сортировку по одному элементу, скажем, по высокому / короткому элементу, я мог бы сделать это через s = sorted(s, key = itemgetter(1)).

Если бы я хотел выполнить сортировку по обоим параметрам высоты / краткости и цвета, я мог бы выполнить сортировку дважды, по одному разу для каждого элемента, но есть ли более быстрый способ?

Переведено автоматически
Ответ 1

Ключом может быть функция, возвращающая кортеж:

s = sorted(s, key = lambda x: (x[1], x[2]))

Или вы можете добиться того же с помощью itemgetter (что быстрее и позволяет избежать вызова функции Python):

import operator
s = sorted(s, key = operator.itemgetter(1, 2))

И обратите внимание, что здесь вы можете использовать sort вместо использования sorted с последующим переназначением:

s.sort(key = operator.itemgetter(1, 2))
Ответ 2

Я не уверен, что это самый простой метод python ... У меня был список кортежей, в котором требовалась сортировка 1-го по убыванию целых значений и 2-го по алфавиту. Для этого потребовалось изменить сортировку по целым числам, но не по алфавиту. Вот мое решение: (кстати, на лету на экзамене я даже не знал, что вы можете "вложить" отсортированные функции)

a = [('Al', 2),('Bill', 1),('Carol', 2), ('Abel', 3), ('Zeke', 2), ('Chris', 1)]  
b = sorted(sorted(a, key = lambda x : x[0]), key = lambda x : x[1], reverse = True)
print(b)
[('Abel', 3), ('Al', 2), ('Carol', 2), ('Zeke', 2), ('Bill', 1), ('Chris', 1)]
Ответ 3

Опоздание на вечеринку на несколько лет, но я хочу как сортировать по 2 критериям , так и использовать reverse=True. На случай, если кто-то еще захочет узнать, как это сделать, вы можете заключить свои критерии (функции) в круглые скобки:

s = sorted(my_list, key=lambda i: ( criteria_1(i), criteria_2(i) ), reverse=True)
Ответ 4

Похоже, вы могли бы использовать list вместо tuple. Я думаю, это становится более важным, когда вы захватываете атрибуты вместо "магических индексов" списка / кортежа.

В моем случае я хотел выполнить сортировку по нескольким атрибутам класса, где входящими ключами были строки. Мне нужна была разная сортировка в разных местах, и я хотел общую сортировку по умолчанию для родительского класса, с которым взаимодействовали клиенты; нужно было переопределять "ключи сортировки" только тогда, когда мне действительно "это было нужно", но также таким образом, чтобы я мог хранить их в виде списков, которыми класс мог делиться

Итак, сначала я определил вспомогательный метод

def attr_sort(self, attrs=['someAttributeString']:
'''helper to sort by the attributes named by strings of attrs in order'''
return lambda k: [ getattr(k, attr) for attr in attrs ]

затем использовать его

# would defined elsewhere but showing here for consiseness
self.SortListA = ['attrA', 'attrB']
self.SortListB = ['attrC', 'attrA']
records = .... #list of my objects to sort
records.sort(key=self.attr_sort(attrs=self.SortListA))
# perhaps later nearby or in another function
more_records = .... #another list
more_records.sort(key=self.attr_sort(attrs=self.SortListB))

При этом будет использоваться сгенерированная лямбда-функция сортировки списка по object.attrA, а затем object.attrB предполагается, object что у нее есть геттер, соответствующий предоставленным именам строк. И во втором случае будет выполняться сортировка по object.attrC then object.attrA.

Это также позволяет вам потенциально предоставлять варианты внешней сортировки для одинакового использования потребителем, модульным тестом или для того, чтобы они, возможно, сообщали вам, как они хотят, чтобы сортировка выполнялась для какой-либо операции в вашем api, просто предоставляя вам список и не связывая их с вашей серверной реализацией.

python sorting