Сортировка списка Python по двум полям - PullRequest
146 голосов
/ 06 марта 2011

У меня есть следующий список, созданный из отсортированного csv

list1 = sorted(csv1, key=operator.itemgetter(1))

Я бы на самом деле хотел отсортировать список по двум критериям: сначала по значению в поле 1, а затем по значению в поле 2.Как мне это сделать?

Ответы [ 7 ]

269 голосов
/ 14 июня 2013

Ответ на этот мертвый поток для архива.

Нет необходимости импортировать что-либо при использовании лямбда-функций.
Следующие сортировки list по первому элементу, затем по второму элементу.

sorted(list, key=lambda x: (x[0], -x[1]))
142 голосов
/ 06 марта 2011

как это:

import operator
list1 = sorted(csv1, key=operator.itemgetter(1, 2))
18 голосов
/ 06 марта 2011

Python имеет стабильную сортировку, поэтому при условии, что производительность не является проблемой, проще всего отсортировать ее по полю 2, а затем снова отсортировать по полю 1.

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

list1 = sorted(csv1, key=operator.itemgetter(2))
list1 = sorted(list1, key=operator.itemgetter(1))

Выполнение этого способа также облегчает обработкуВ ситуации, когда вы хотите, чтобы некоторые столбцы сортировались в обратном порядке, просто добавьте параметр 'reverse = True', когда это необходимо.

В противном случае вы можете передать несколько параметров в itemgetter или вручную создать кортеж.Вероятно, это будет быстрее, но проблема в том, что он плохо обобщается, если некоторые столбцы хотят быть отсортированы в обратном порядке (числовые столбцы все еще можно перевернуть путем их отрицания, но это мешает стабильности сортировки).

Так что, если вам не нужны никакие столбцы с обратной сортировкой, перейдите к множеству аргументов для itemgetter, если это возможно, и столбцы не являются числовыми, или вы хотите, чтобы сортировка оставалась стабильной, для нескольких последовательных сортировок.

Редактировать: Для комментаторов, у которых есть проблемы с пониманием того, как это отвечает на исходный вопрос, вот пример, который точно показывает, как стабильный характер сортировки гарантирует, что мы можем выполнять отдельные сортировки для каждого ключа ив итоге получаются данные, отсортированные по нескольким критериям:

DATA = [
    ('Jones', 'Jane', 58),
    ('Smith', 'Anne', 30),
    ('Jones', 'Fred', 30),
    ('Smith', 'John', 60),
    ('Smith', 'Fred', 30),
    ('Jones', 'Anne', 30),
    ('Smith', 'Jane', 58),
    ('Smith', 'Twin2', 3),
    ('Jones', 'John', 60),
    ('Smith', 'Twin1', 3),
    ('Jones', 'Twin1', 3),
    ('Jones', 'Twin2', 3)
]

# Sort by Surname, Age DESCENDING, Firstname
print("Initial data in random order")
for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

print('''
First we sort by first name, after this pass all
Twin1 come before Twin2 and Anne comes before Fred''')
DATA.sort(key=lambda row: row[1])

for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

print('''
Second pass: sort by age in descending order.
Note that after this pass rows are sorted by age but
Twin1/Twin2 and Anne/Fred pairs are still in correct
firstname order.''')
DATA.sort(key=lambda row: row[2], reverse=True)
for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

print('''
Final pass sorts the Jones from the Smiths.
Within each family members are sorted by age but equal
age members are sorted by first name.
''')
DATA.sort(key=lambda row: row[0])
for d in DATA:
    print("{:10s} {:10s} {}".format(*d))

Это работоспособный пример, но для спасения людей, выполняющих его, вывод:

Initial data in random order
Jones      Jane       58
Smith      Anne       30
Jones      Fred       30
Smith      John       60
Smith      Fred       30
Jones      Anne       30
Smith      Jane       58
Smith      Twin2      3
Jones      John       60
Smith      Twin1      3
Jones      Twin1      3
Jones      Twin2      3

First we sort by first name, after this pass all
Twin1 come before Twin2 and Anne comes before Fred
Smith      Anne       30
Jones      Anne       30
Jones      Fred       30
Smith      Fred       30
Jones      Jane       58
Smith      Jane       58
Smith      John       60
Jones      John       60
Smith      Twin1      3
Jones      Twin1      3
Smith      Twin2      3
Jones      Twin2      3

Second pass: sort by age in descending order.
Note that after this pass rows are sorted by age but
Twin1/Twin2 and Anne/Fred pairs are still in correct
firstname order.
Smith      John       60
Jones      John       60
Jones      Jane       58
Smith      Jane       58
Smith      Anne       30
Jones      Anne       30
Jones      Fred       30
Smith      Fred       30
Smith      Twin1      3
Jones      Twin1      3
Smith      Twin2      3
Jones      Twin2      3

Final pass sorts the Jones from the Smiths.
Within each family members are sorted by age but equal
age members are sorted by first name.

Jones      John       60
Jones      Jane       58
Jones      Anne       30
Jones      Fred       30
Jones      Twin1      3
Jones      Twin2      3
Smith      John       60
Smith      Jane       58
Smith      Anne       30
Smith      Fred       30
Smith      Twin1      3
Smith      Twin2      3

Обратите внимание, в частности, как во второмшаг reverse=True параметр сохраняет имена в порядке, в то время как простая сортировка, а затем обратный список будетвыберите желаемый порядок для третьего ключа сортировки.

5 голосов
/ 06 марта 2011
def keyfunc(x):
    return tuple(x[1],x[2])

list1 = sorted(csv1, key=keyfunc)
3 голосов
/ 20 июня 2018
employees.sort(key = lambda x:x[1])
employees.sort(key = lambda x:x[0])

Мы также можем использовать .sort с лямбдой 2 раза, потому что сортировка Python установлена ​​и стабильна Сначала будет отсортирован список по второму элементу x [1]. Затем будет отсортирован первый элемент, x [0] (самый высокий приоритет).

сотрудников [0] = имя сотрудника сотрудники [1] = зарплата сотрудника

Это эквивалентно выполнению следующих действий: сотрудники.sort (ключ = лямбда х: (х [0], х [1]))

1 голос
/ 22 мая 2019

В порядке возрастания вы можете использовать:

sorted_data= sorted(non_sorted_data, key=lambda k: (k[1],k[0]))

или в порядке убывания вы можете использовать:

sorted_data= sorted(non_sorted_data, key=lambda k: (k[1],k[0]),reverse=True)
0 голосов
/ 20 февраля 2019

Сортировка списка диктов с использованием ниже приведет к сортировке списка в порядке убывания по первому столбцу по зарплате и по второму столбцу по возрасту

d=[{'salary':123,'age':23},{'salary':123,'age':25}]
d=sorted(d, key=lambda i: (i['salary'], i['age']),reverse=True)

Вывод: [{'salary': 123, 'age': 25}, {'зарплата': 123, 'возраст': 23}]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...