2011-03-06 74 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)