这个问题在这里已有答案:
是否有一种简单的方法可以使用列表推导来展平迭代列表,或者失败,你会认为什么是 balancer 这样的浅层列表, balancer 性能和可读性的最佳方法?
我尝试使用嵌套列表理解来压缩这样的列表,如下所示:
[image for image in menuitem for menuitem in list_of_menuitems]
但是我在那里遇到麻烦,因为 name 'menuitem' is not defined
. 在谷歌搜索和浏览Stack Overflow后,我得到了 reduce
语句所需的结果:
reduce(list.__add__, map(lambda x: list(x), list_of_menuitems))
但是这个方法是不可读的,因为我需要在那里调用 list(x)
因为x是一个Django QuerySet
对象 .
Conclusion :
感谢所有为此问题做出贡献的人 . 以下是我学到的内容摘要 . 我还将其作为社区维基,以防其他人想要添加或更正这些观察结果 .
我原来的reduce语句是多余的,用这种方式编写得更好:
>>> reduce(list.__add__, (list(mi) for mi in list_of_menuitems))
这是嵌套列表理解的正确语法(Brilliant summary dF!):
>>> [image for mi in list_of_menuitems for image in mi]
但这些方法都不如使用 itertools.chain
那样有效:
>>> from itertools import chain
>>> list(chain(*list_of_menuitems))
正如@cdleary指出的那样,通过使用 chain.from_iterable
来避免*操作员魔法可能是更好的风格:
>>> chain = itertools.chain.from_iterable([[1,2],[3],[5,89],[],[6]])
>>> print(list(chain))
>>> [1, 2, 3, 5, 89, 6]
23 回答
在Python 2.6中,使用chain.from_iterable():
它避免了创建中间列表 .
你试过扁平吗?从matplotlib.cbook.flatten(seq, scalarp=)?
UPDATE 这给了我另一个想法:
因此,要测试递归变深时的效果:更深入多少?
我打赌“flattenlist”我将使用这个而不是matploblib很长一段时间,除非我想要一个yield yield和快速的结果,因为“flatten”在matploblib.cbook中使用
这个很快 .
:
测试:
pylab提供了一个展平:link to numpy flatten
如果您正在寻找内置的,简单的单线,您可以使用:
回报
@S.Lott:你激励我写一个timeit应用程序 .
我认为它也会根据分区数量(容器列表中的迭代器数量)而有所不同 - 您的评论未提及30个项目中有多少个分区 . 这个图在每次运行中展平了一千个项目,分区数量不同 . 项目均匀分布在分区中 .
代码(Python 2.6):
Edit: 决定将其作为社区维基 .
Note:
METHODS
应该与装饰者积累,但我认为人们更容易阅读这种方式 .表现结果 . 修订 .
我将30个项目的2级列表展平1000次
减少总是一个糟糕的选择 .
sum(list of lists, [])
会压扁它 .此解决方案适用于任意嵌套深度 - 不仅仅是“列表列表”深度,其他解决方案的一些(全部?)仅限于:
它是允许任意深度嵌套的递归 - 直到你达到最大递归深度,当然......
在Python 2或3中实现此目的的最简单方法是使用morph来使用morph .
代码是:
这是一个使用
collectons.Iterable
的多级列表工作的版本:如果您需要可索引序列,请考虑itertools.chain and company .
它将适用于's iterable, which should include Django' s iterable
QuerySet
s,它似乎是你在问题中使用的 .Edit: 无论如何,这可能与reduce一样好,因为reduce会将项目复制到正在扩展的列表中 . 如果你在最后运行
list(chain)
,chain
只会产生这个(相同的)开销 .Meta-Edit: 实际上,它是's less overhead than the question'提出的解决方案,因为当您使用临时扩展原始文件时,您会丢弃您创建的临时列表 .
Edit: 由于J.F. Sebastian says
itertools.chain.from_iterable
避免了拆包,你应该使用它来避免*
魔法,但the timeit app显示可忽略不计的性能差异 .关于什么:
但是,Guido建议不要在一行代码中执行太多操作,因为它会降低可读性 . 通过在单行和多行中执行您想要的操作,可以获得最小的性能提升(如果有的话) .
一个简单的替代方法是使用numpy's concatenate但它将内容转换为float:
似乎与
operator.add
混淆了!当您将两个列表一起添加时,正确的术语是concat
,而不是添加 .operator.concat
是您需要使用的 .如果您正在考虑功能,它就像这样简单::
你看到reduce尊重序列类型,所以当你提供一个元组时,你会得到一个元组 . 让我们尝试一下清单::
啊哈,你得到一份清单 .
性能怎么样::
from_iterable非常快!但这没有比较减少与concat .
在Python 3.4你将能够做到:
根据我的经验,压缩列表列表的最有效方法是:
与其他提议的方法进行一些时间比较:
现在,处理更长的子列表时效率提升似乎更好:
此方法也适用于任何迭代对象:
在我的头顶,你可以消除lambda:
或者甚至消除 Map ,因为你已经有了list-comp:
您也可以将其表达为列表总和:
如果列表中的每个项都是一个字符串(并且这些字符串中的任何字符串都使用" "而不是' '),则可以使用正则表达式(
re
module)上面的代码将in_list转换为字符串,使用正则表达式查找引号内的所有子字符串(即列表中的每个项目)并将它们作为列表吐出 .
如果您必须使用不可迭代的元素或深度超过2的平面更复杂的列表,您可以使用以下函数:
它将返回生成器对象,您可以使用
list()
函数将其转换为列表 . 请注意,python3.3提供了yield from
语法,但您可以使用显式迭代 .例:
这个版本是一个生成器 . 如果你想要一个列表,那就去吧 .
如果想要展平满足条件的谓词,可以添加谓词
取自python cookbook
你几乎拥有它! way to do nested list comprehensions将
for
语句的顺序与常规嵌套for
语句中的顺序相同 .因此,这
对应于
所以你要
这是使用列表推导的正确解决方案(它们在问题中是向后的):
在你的情况下,它会
或者你可以使用
join
然后说在任何一种情况下,陷阱都是
for
循环的嵌套 .