2013-07-13 112 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的任何信息。