2012-09-11 69 views
3

我有一個列表爲[[4,5,6],[2,3,1]]。現在我想根據list[1]對列表進行排序,即輸出應該是[[6,4,5],[1,2,3]]。所以基本上我排序2,3,1並保持訂單list[0]基於python中的嵌套列表之一列表中的一個排序

在搜索時,我得到了一個函數,它根據每個列表的第一個元素進行排序,但不是這樣。此外,我不想重新創建列表[[4,2],[5,3],[6,1]],然後使用該功能。

+3

歡迎來到Stack Overflow!我們鼓勵你[研究你的問題](http://stackoverflow.com/questions/how-to-ask)。如果你已經[嘗試了某些東西](http://whathaveyoutried.com/),請將其添加到問題中 - 如果沒有,請先研究並嘗試您的問題,然後再回來。 – 2012-09-11 11:04:01

+2

'基本上我正在排序2,3,1並且維護列表[0]的順序' - errr,[6,4,5]!= [4,5,6]?你剛剛在'your_list [1] .sort()'之後? –

+0

從[4,5,6]到[6,4,5]'是什麼樣的? –

回答

7

由於[4, 5, 6][2, 3, 1]有兩個不同的目的,我會做一個函數取參數:該列表將重新排列,且其排序將決定順序列表。我只會返回重新排序的列表。

This answer具有三種不同解決方案的時間表,用於創建排序的排列列表。用最快的選項給出了這樣的解決方案:

def pyargsort(seq): 
    return sorted(range(len(seq)), key=seq.__getitem__) 

def using_pyargsort(a, b): 
    "Reorder the list a the same way as list b would be reordered by a normal sort" 
    return [a[i] for i in pyargsort(b)]      

print using_pyargsort([4, 5, 6], [2, 3, 1]) # [6, 4, 5] 

pyargsort方法由numpyargsort方法,它做同樣的事情更快的啓發。 Numpy還具有高級索引操作,從而可以將數組用作索引,從而可以快速重新排序數組。

所以,如果你需要速度是偉大的,人們會以爲這numpy的解決辦法是更快:

import numpy as np 

def using_numpy(a, b): 
    "Reorder the list a the same way as list b would be reordered by a normal sort" 
    return np.array(a)[np.argsort(b)].tolist() 

print using_numpy([4, 5, 6], [2, 3, 1])  # [6, 4, 5] 

然而,對於短名單(長度< 1000),該解決方案實際上比較慢第一。這是因爲我們首先將ab列表轉換爲array,然後在返回之前將結果轉換回list。如果我們不是假設你正在使用在整個應用程序numpy的陣列,這樣我們就不需要來回轉換,我們得到這樣的解決方案:

def all_numpy(a, b): 
    "Reorder array a the same way as array b would be reordered by a normal sort" 
    return a[np.argsort(b)] 

print all_numpy(np.array([4, 5, 6]), np.array([2, 3, 1])) # array([6, 4, 5]) 

all_numpy函數執行起來比using_pyargsort功能快10倍。

下面的logaritmic圖將這三個解決方案與其他答案中的兩個替代解決方案進行了比較。參數是兩個等長的隨機洗牌範圍,並且這些函數都接收相同的有序列表。我只計算函數執行的時間。出於說明的目的,我在每個numpy解決方案的額外圖形行中添加了60毫秒的加載numpy開銷的時間。

enter image description here

正如我們所看到的,全numpy的解決方案由一個量級擊敗別人。從python list轉換回來,相比之下,using_numpy解決方案的速度顯着下降,但它仍然勝過大型列表的純Python。

對於列表長度約爲1,000'000,using_pyargsort需要2.0秒,using_nympy +開銷只有1.3秒,而all_numpy +開銷爲0.3秒。

+3

不需要安裝第三方庫來完成簡單的任務,比如排序列表...... numpy不是標準python安裝的一部分。 – l4mpi

+2

@ l4mpi再次閱讀問題。這不是一個標準的排序,但重新排列列表中的第一個項目的方式與第二個項目的標準排序方式相同。此外,downvote *表示*「此答案無用」。如果有人已經使用numpy,這個答案*是有用的,即使沒有,它也會提供一個選項。你的downvote是不合適的。 –

+1

它從我身上獲得+1是一種完美可行的方法。閱讀比排序/ zip /解包代碼更容易。此外,大多數Linux發行版都有標準的numpy,如果OP冒險進入這種「不尋常」的東西 - 這是一個非常值得選擇的選擇... –

5

您描述的排序不是很容易完成。我能想到的做到這一點的唯一方法是使用zip創建你說你的列表不想創建:

lst = [[4,5,6],[2,3,1]] 
# key = operator.itemgetter(1) works too, and may be slightly faster ... 
transpose_sort = sorted(zip(*lst),key = lambda x: x[1]) 
lst = zip(*transpose_sort) 

是否有此限制的一個原因?

(另請注意,你可以做到這一切在一個行,如果你真的想:

lst = zip(*sorted(zip(*lst),key = lambda x: x[1])) 

這也導致元組的列表。如果你真的想要一個列表的列表,你可以map結果:

lst = map(list, lst) 

或列表理解將工作以及:

lst = [ list(x) for x in lst ] 
+0

避免映射:'[list(t)for zip in zip(* sorted(zip(* [[4,5,6],[2,3,1]]),key = lambda x:x [1]) )]' 但我猜'list(zip(* sorted(zip(* [[4,5,6],[2,3,1]]),key = lambda x:x [1]))[ 0])'是他真正想要的。 – Alfe

+0

@Alfe - 我看不出有什麼理由避免使用map來支持list-comp(除了它對於py2k和py3k我都是一樣的)。 – mgilson

+0

對不起,我的簡潔;我的意思是「避免地圖」(以防萬一你想,我通常這樣做)。如果l [1]中的數字出現多次, – Alfe

0

如果第二列表中不包含重複,你可能只是這樣做:

l = [[4,5,6],[2,3,1]] #the list 
l1 = l[1][:]   #a copy of the to-be-sorted sublist 
l[1].sort()    #sort the sublist 
l[0] = [l[0][l1.index(x)] for x in l[1]] #order the first sublist accordingly 

(因爲這節省了子列表L [1]這可能是一個糟糕的主意,如果你輸入列表是巨大的)

+0

將失敗。 – Alfe

+0

我在Answer中說過,不需要downvote ... OP沒有指定他的列表是否包含重複項,如果是,那麼第一個列表的順序不會是確定性的。例如。 '[[1,2,3],[5,4,5]]'可以是[[2,1,3],[4,5,5]]或[[2,3,1] ,[4,5,5]] ...... – l4mpi

+0

沒有。如果值在l [1]中出現超過一次,則l [0]中的某些值將被重複,而其他值完全不會出現。那麼你的結果就不是輸入的排序版本(例如,你爲'l = [[4,5,6],[2,2,1]]'返回'[6,4,4]''因爲提問者沒有指定值不能在l [1]中出現超過一次,你不能假定這個(或者至少在你指定的時候大聲地指定它) – Alfe

0

這個怎麼樣:

a = [[4,5,6],[2,3,1]] 
[a[0][i] for i in sorted(range(len(a[1])), key=lambda x: a[1][x])] 

它採用的主要方式numpy的做它,而不必使用numpy的和不帶拉鍊的東西。

無論是使用numpy還是周圍的壓縮似乎都不是最適合巨型結構的方式。不幸的是,.sort()方法內置在list類型中,並使用對列表中的元素進行硬連線訪問(覆蓋__getitem__()或類似的函數在這裏沒有任何影響)。

所以你可以實現你自己的sort()根據其中的值對兩個或多個列表進行排序;這基本上是numpy所做的。

或者您可以創建一個值列表進行排序,排序,然後重新創建排序後的原始列表。

+0

啊,我現在看到上面的numpy版本現在也被這個解決方案修改了(在那裏稱爲pyargsort)。 – Alfe