2011-03-06 101 views
113

Python列表我有一个排序的CSV排序由两个标准

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

创建以下列表我真的想通过两个标准排序列表:现场1的第一个由值,然后在字段2中的值。我该怎么做?

+0

[按多个属性对列表进行排序?](htt ps://stackoverflow.com/questions/4233476/sort-a-list-by-multiple-attributes) – 2017-08-03 08:34:59

回答

114

这样的:

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

+1:比我更优雅。我忘记了itemgetter可以采取多种指标。 – dappawit 2011-03-06 19:43:14

+0

@half full:很高兴帮助:) – mouad 2011-03-06 19:53:33

+7

'operator'是一个需要导入的模块。 – trapicki 2013-08-28 14:45:56

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

list1 = sorted(csv1, key=keyfunc) 
+3

我不认为'tuple()'可以接收两个参数(或者更确切地说,三个,如果你用'self'计数) – 2012-12-12 23:15:59

+2

元组只需要一个参数 – therealprashant 2015-06-06 11:02:03

+0

'return'语句应该是'return tuple((x [1],x [2]))'或简单地'return x [1],x [2]'。 [Refer](http://stackoverflow.com/a/17109098/4582603)@jaap下面的答案,如果你正在寻找不同的方向排序 – 2017-02-11 01:40:59

14

Python有一个稳定的排序,所以提供的性能是不是一个问题,最简单的方法是通过现场2对它进行排序,并在排序再由场1 。

这会给你你想要的结果,唯一的缺点是,如果它是一个大名单(或要经常对其进行排序)调用两次排序可能是不可接受的开销。

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

这样做,这样也更容易处理,你想要一些列的排序颠倒的情况,只包括“逆= 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参数保持名字顺序,而简单排序然后反转列表将失去第三个排序键所需的顺序。

+0

谢谢,这是非常有益的。 – 2011-03-06 19:53:16

+1

稳定的排序并不意味着它不会忘记你之前的排序是什么。这个答案是错误的。 – 2011-03-06 21:10:30

+5

稳定的排序意味着您可以按列a,b,c进行排序,只需按列c进行排序,然后按b进行排序即可。除非你喜欢扩大你的评论,否则我认为你是错的。 – Duncan 2011-03-06 21:23:06

214

回复归档这个死线程。

无需使用lambda函数时导入任何东西。
以下各种list由第一元件,然后通过第二元件。

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

我喜欢这个解决方案,因为您可以将字符串转换为int,以便进行排序,例如:'lambda x:(x [ 0],INT(X [1]))'。 +1 – pbible 2014-09-10 13:41:49

+7

不错。正如您在上述主要答案的评论中所指出的那样,这是用不同的排序顺序进行多种排序的最佳(唯一?)方式。也许强调这一点。此外,您的文本并不表示您按第二个元素降序排序。 – PeterVermont 2015-06-12 14:25:16

+0

另外如果'x [1]'是日期?我应该将其转换为整数吗? @pbible将字符串转换为int保留字符串的字母顺序? – user1700890 2015-11-20 23:32:02

0

假设要排序包含数字,比如说一个字符串数组,从

["date_2015-1-1", "date_2015-1-10", "date_2015-1-2"] 

["date_2015-1-1", "date_2015-1-2", "date_2015-1-10"] 

你可以这样来做:

import re 

def sort_key(_str): 
    return [ int(s) if s.isdigit() else s for s in re.split(r'(\d+)', _str) ] 

arr = ["date_2015-1-1", "date_2015-1-10", "date_2015-1-2"] 
sorted(arr, key=sort_key)