2013-07-13 113 views
4

一種方式來分類遍歷一對iterables a的和b按排序順序是鏈它們和排序鏈式迭代:迭代在一對iterables的,由屬性

for i in sorted(chain(a, b)): 
    print i 

例如,如果每一個的元件可迭代是:

a: 4, 6, 1 
b: 8, 3 

然後該構建將產生元件的順序

1, 3, 4, 6, 8 

但是,如果迭代對對象進行迭代,則會按內存地址對對象進行排序。假設每個迭代遍歷同一類型的對象,

  1. 什麼是最快方式來遍歷特定 屬性的對象,該屬性排序?

  2. 如果在迭代中要選擇的屬性不同,該怎麼辦?如果iterables ab兩疊代foo類型的對象,其屬性foo.x和相同類型的foo.y,怎麼可能一個疊代的a元素通過xb排序由y排序?

對於#2的示例中,如果

a: (x=4,y=3), (x=6,y=2), (x=1,y=7) 
b: (x=2,y=8), (x=2,y=3) 

則元件應在順序

1, 3, 4, 6, 8 

如前製備。請注意,只有來自ax屬性和來自by屬性纔會進入排序和結果。

+1

關於第二個問題:在排序是如何合併?你能提供一個例子嗎? –

+0

@TimPietzcker因爲根據問題'foo.x'和'foo.y'屬於同一類型,直覺上我會說OP會期望整個批次被排序在一個假想的'foo.z'上,等於相關的每個迭代的屬性。 –

+0

@ZeroPiraeus基本上是的。 –

回答

3

Tim Pietzcker已經爲您對每個迭代使用相同屬性的情況作出了回答。如果您使用的是同一類型的不同屬性,你可以做這樣的(使用複數作爲具有相同類型的兩個屬性的現成的類):

在Python 2:

>>> a = [1+4j, 7+0j, 3+6j, 9+2j, 5+8j] 
>>> b = [2+5j, 8+1j, 4+7j, 0+3j, 6+9j] 
>>> keyed_a = ((n.real, n) for n in a) 
>>> keyed_b = ((n.imag, n) for n in b) 
>>> from itertools import chain 
>>> sorted_ab = zip(*sorted(chain(keyed_a, keyed_b), key=lambda t: t[0]))[1] 
>>> sorted_ab 
((1+4j), (8+1j), (3+6j), 3j, (5+8j), (2+5j), (7+0j), (4+7j), (9+2j), (6+9j)) 

由於在Python 3 zip()返回一個迭代,我們需要嘗試下標之前將其強制到一個列表:

>>> # ... as before up to 'from itertools import chain' 
>>> sorted_ab = list(zip(*sorted(chain(keyed_a, keyed_b), key=lambda t: t[0])))[1] 
>>> sorted_ab 
((1+4j), (8+1j), (3+6j), 3j, (5+8j), (2+5j), (7+0j), (4+7j), (9+2j), (6+9j)) 
+0

你總是可以將zip函數封裝在python3的list()中,它將包含迭代器的整個輸出: 'list(zip(* sorted(chain(keyed_a,keyed_b),key = lambda t:t [ 0])))[1]' – Ole

+0

@歐是的,這是一個更好的主意。相應更新:-) –

2

對問題1的回答:您可以提供key屬性至sorted()。例如,如果你想通過對象的.name進行排序,然後使用

sorted(chain(a, b), key=lambda x: x.name) 

至於問題2:我想你需要另一個屬性爲每個對象(如foo.z,由零比雷埃夫斯的建議),可由sorted()訪問,因爲該函數無法告訴它當前排序的對象來自哪裏。畢竟,它從chain()接收到一個新的迭代器,它不包含有關當前元素是否來自ab的任何信息。