如果我有序列序列(可能是元组列表),我可以使用itertools.chain()来展平它.但有时我觉得我宁愿把它写成一种理解.我只是想不出怎么做.这是一个非常具体的案例:
假设我想在序列中交换每对元素.我在这里使用字符串作为序列:
>>> from itertools import chain >>> seq = '012345' >>> swapped_pairs = zip(seq[1::2], seq[::2]) >>> swapped_pairs [('1', '0'), ('3', '2'), ('5', '4')] >>> "".join(chain(*swapped_pairs)) '103254'
我在序列的偶数和奇数切片上使用zip来交换对.但我最终得到了一个现在需要扁平化的元组列表.所以我使用chain().有没有办法可以用理解来表达它?
如果你想发布你自己的解决方案来解决交换对的元素的基本问题,请继续,我会投票给任何教我新东西的东西.但是,即使答案是"不,你做不到",我也只会接受一个针对我的问题的答案.
理解力?好...
>>> seq = '012345' >>> swapped_pairs = zip(seq[1::2], seq[::2]) >>> ''.join(item for pair in swapped_pairs for item in pair) '103254'
我发现最快的是从一个空数组开始并扩展它:
In [1]: a = [['abc', 'def'], ['ghi'],['xzy']] In [2]: result = [] In [3]: extend = result.extend In [4]: for l in a: ...: extend(l) ...: In [5]: result Out[5]: ['abc', 'def', 'ghi', 'xzy']
对于Alex Martelli尝试的例子,这个速度快了两倍:在Python列表中列出一个平面列表
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]' 10000 loops, best of 3: 86.3 usec per loop $ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'b = []' 'extend = b.extend' 'for sub in l:' ' extend(sub)' 10000 loops, best of 3: 36.6 usec per loop
我想出了这个,因为我预感到幕后,extend会为列表分配适量的内存,并且可能会使用一些低级代码来移动项目.我不知道这是否属实,但是谁在乎,它更快.
顺便说一下,它只是线性加速:
$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]' 'b = []' 'extend = b.extend' 'for sub in l:' ' extend(sub)' 1000000 loops, best of 3: 0.844 usec per loop $ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]' '[item for sublist in l for item in sublist]' 1000000 loops, best of 3: 1.56 usec per loop
您也可以使用map(results.extend, a)
,但这会慢,因为它正在构建自己的Nones列表.
它还为您提供了不使用函数式编程的一些好处.即
您可以扩展现有列表而不是创建一个空列表,
您仍然可以一目了然,几分钟,几天甚至几个月后了解代码.
顺便说一下,最好避免列表理解.小的并不是太糟糕,但总的来说,列表理解实际上并没有为你节省太多的打字,但往往难以理解并且很难改变或重构(曾经看过三级列表理解?).除了简单的情况外,Google编码指南会针对他们提供建议.我的观点是它们只适用于"丢弃"代码,即作者不关心可读性的代码,或者已知永远不需要将来维护的代码.
比较这两种写同一件事的方式:
result = [item for sublist in l for item in sublist]
有了这个:
result = [] for sublist in l: for item in sublist: result.append(item)
YMMV,但是第一个阻止了我,我不得不考虑它.在第二个中,嵌套从缩进中显而易见.