用两个字段对Python列表进行排序

2024-06-13 18:43:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我用排序后的csv创建了以下列表

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

实际上,我想按两个条件对列表进行排序:首先按字段1中的值排序,然后按字段2中的值排序。我该怎么做?


Tags: csvkey列表排序条件operatorsortedlist1
3条回答

像这样:

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

Python有一个稳定的排序,因此如果性能不是问题,最简单的方法是按字段2排序,然后按字段1再次排序。

这将给你想要的结果,唯一的问题是如果它是一个大列表(或者你想经常排序),调用sort两次可能是一个不可接受的开销。

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参数如何使名字保持顺序,而简单地排序然后反转列表将丢失第三个排序键所需的顺序。

正在回复存档的死线程。

使用lambda函数时无需导入任何内容。
下面按第一个元素对list排序,然后按第二个元素排序。

sorted(list, key=lambda x: (x[0], -x[1]))

相关问题 更多 >