按两个字段排序Python列表
我有一个从已排序的csv文件中创建的列表
list1 = sorted(csv1, key=operator.itemgetter(1))
我实际上想根据两个标准来排序这个列表:首先根据字段1的值排序,然后根据字段2的值排序。我该怎么做呢?
10 个回答
29
Python有一种稳定的排序方式,所以如果性能不是问题,最简单的方法就是先按第二个字段排序,然后再按第一个字段排序。
这样就能得到你想要的结果,唯一需要注意的是,如果列表很大(或者你需要频繁排序),那么调用两次排序可能会带来不必要的负担。
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
参数保持了名字的顺序,而简单地排序再反转列表会导致第三个排序关键字的顺序丢失。
461
使用lambda函数时,不需要导入任何东西。
下面的代码是根据列表中每个元素的第一个值进行排序,然后再根据第二个值进行排序。你还可以选择一个字段升序排序,另一个字段降序排序,比如这样:
sorted_list = sorted(list, key=lambda x: (x[0], -x[1]))
183
像这样:
import operator
list1 = sorted(csv1, key=operator.itemgetter(1, 2))