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

hal*_*ull 153 python sorting

我有一个从排序的csv创建的以下列表

list1 = sorted(csv1, key=operator.itemgetter(1))
Run Code Online (Sandbox Code Playgroud)

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

jaa*_*aap 287

回复此死线程进行存档.

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

sorted(list, key=lambda x: (x[0], -x[1]))
Run Code Online (Sandbox Code Playgroud)

  • 尼斯.正如您在上面的主要答案的评论中所指出的,这是使用不同排序顺序进行多种排序的最佳(唯一?)方式.或许强调一下.此外,您的文本并不表示您在第二个元素上降序排序. (9认同)
  • @jan它反向排序 (6认同)
  • `-x [1]`中的`-`代表什么? (3认同)
  • 不会在一个特定的情况下工作.接受的解决方案也不起作用.例如,要用作键的列都是无法转换为数字的字符串.其次,想要按升序排序一列,降序排序另一列. (3认同)
  • @ user1700890我假设该字段已经是字符串.默认情况下,它应按字母顺序对字符串进行排序.如果与此处的答案或OP的原始问题没有特别相关,您应该单独发布您自己的问题. (2认同)

mou*_*uad 147

像这样:

import operator
list1 = sorted(csv1, key=operator.itemgetter(1, 2))
Run Code Online (Sandbox Code Playgroud)

  • `operator`是一个需要导入的模块. (7认同)
  • @ashish,看下面我的回答用lambda函数这很清楚,按"-x [1]"或"x [0] + x [1]"排序如果你愿意的话 (3认同)
  • +1:比我的更优雅。我忘记了 itemgetter 可以采用多个索引。 (2认同)
  • 如果我想在一个元素上升序并在其他元素上降序,使用itemgetter,我将如何继续? (2认同)

Dun*_*can 18

Python具有稳定的排序,因此只要性能不是问题,最简单的方法是按字段2对其进行排序,然后再按字段1对其进行排序.

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

list1 = sorted(csv1, key=operator.itemgetter(2))
list1 = sorted(list1, key=operator.itemgetter(1))
Run Code Online (Sandbox Code Playgroud)

这样做也可以很容易地处理您希望某些列反向排序的情况,只需在必要时包含'reverse = True'参数.

否则,您可以将多个参数传递给itemgetter或手动构建元组.这可能会更快,但有一个问题是,如果某些列想要反向排序它们不能很好地推广(数字列仍然可以通过否定它们来反转,但这会使排序保持稳定).

因此,如果您不需要任何反向排序的列,请为itemgetter添加多个参数(如果可能),并且列不是数字,或者您希望保持sort stable连续多个排序.

编辑:对于在理解如何回答原始问题时遇到问题的评论者,这里有一个示例,它确切地说明了排序的稳定性如何确保我们可以对每个键进行单独排序,最终得到按多个标准排序的数据:

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))
Run Code Online (Sandbox Code Playgroud)

这是一个可运行的示例,但为了节省运行它的人,输出是:

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
Run Code Online (Sandbox Code Playgroud)

请特别注意,在第二步中,reverse=True参数如何按顺序保存第一个名称,而简单排序然后反转列表将失去第三个排序键的所需顺序.

  • 这个答案肯定是正确的,虽然对于较大的列表,它是不理想的:如果列表已经部分排序,那么你将通过改变列表更多地丢失大部分Python的排序优化.@Mike,你错了; 我建议在宣布错误之前先测试答案. (6认同)
  • @MikeAxiak:http://docs.python.org/2/library/stdtypes.html#index-29在评论9中说:_启动Python 2.3,sort()方法保证稳定.如果排序保证不改变比较相等的元素的相对顺序,那么排序是稳定的 - 这对于多次传递中的排序是有帮助的**(例如,按部门排序,然后按工资等级排序)._ (6认同)
  • 稳定的排序意味着您可以按列a,b,c进行排序,只需按列c排序然后排序a.除非你愿意扩展你的评论,否则我认为你错了. (5认同)
  • 稳定排序并不意味着它不会忘记您之前的排序是什么。这个答案是错误的。 (2认同)

dap*_*wit 5

def keyfunc(x):
    return tuple(x[1],x[2])

list1 = sorted(csv1, key=keyfunc)
Run Code Online (Sandbox Code Playgroud)

  • 我不认为`tuple()`可以接收两个参数(或者更确切地说,三个,如果你用'self`计算) (3认同)
  • 元组只需要一个参数 (3认同)