如果我有序列序列(可能是元组列表),我可以使用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()。有没有办法可以用理解来表达它?
如果你想发布你自己的解决方案来解决交换对的元素的基本问题,那么,我会投票给任何教会我新东西的东西。但我只会将接受的答案标记为我的问题,即使答案是“不,你不能。”。
答案 0 :(得分:29)
理解力?嗯......
>>> seq = '012345'
>>> swapped_pairs = zip(seq[1::2], seq[::2])
>>> ''.join(item for pair in swapped_pairs for item in pair)
'103254'
答案 1 :(得分:16)
我发现最快的是从一个空数组开始并扩展它:
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尝试的例子的两倍:Making a flat list out of list of lists in 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 coding guidelines advise against them except in simple cases.我的观点是,它们仅适用于“丢弃”代码,即作者不关心可读性的代码,或者已知永远不需要将来维护的代码。
比较这两种写同样的方式:
result = [item for sublist in l for item in sublist]
用这个:
result = []
for sublist in l:
for item in sublist:
result.append(item)
YMMV,但第一个阻止了我,我不得不考虑它。在第二步中,嵌套从缩进中显而易见。
答案 2 :(得分:3)
您可以使用reduce来实现目标:
In [6]: import operator
In [7]: a = [(1, 2), (2,3), (4,5)]
In [8]: reduce(operator.add, a, ())
Out[8]: (1, 2, 2, 3, 4, 5)
这会返回一个元组而不是列表,因为原始列表中的元素是连接的元组。但是你可以轻松地从中构建一个列表,join方法也接受元组。
顺便说一下,列表理解不是正确的工具。基本上,列表推导通过描述该列表的元素应该是什么样来构建新列表。您希望将元素列表减少到只有一个值。
答案 3 :(得分:1)
>>> a = [(1, 2), (3, 4), (5, 6)]
>>> reduce(tuple.__add__, a)
>>> (1, 2, 3, 4, 5, 6)
或者,对内部序列的类型不确定(只要它们都是相同的):
>>> reduce(a[0].__class__.__add__, a)