在 Python 中展平一个浅表 [英] Flattening a shallow list in Python

查看:24
本文介绍了在 Python 中展平一个浅表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一种简单的方法可以通过列表理解来展平可迭代列表,或者如果失败了,你们都认为展平像这样的浅表列表、平衡性能和可读性的最佳方法是什么?

我试图用嵌套列表理解来展平这样的列表,如下所示:

[list_of_menuitems 中 menuitem 的 menuitem 图像的图像]

但是我在那里遇到了 NameError 种类的麻烦,因为 name 'menuitem' 没有定义.在谷歌搜索并环顾 Stack Overflow 后,我使用 reduce 语句得到了想要的结果:

reduce(list.__add__, map(lambda x: list(x), list_of_menuitems))

但是这个方法相当不可读,因为我需要在那里调用 list(x) 因为 x 是一个 Django QuerySet 对象.

结论:

感谢所有为这个问题做出贡献的人.这是我所学到的总结.我还将其设为社区 Wiki,以防其他人想要添加或更正这些观察结果.

我原来的reduce语句是多余的,最好这样写:

<预><代码>>>>reduce(list.__add__, (list(mi) for mi in list_of_menuitems))

这是嵌套列表理解的正确语法(精彩摘要dF!):

<预><代码>>>>[list_of_menuitems 中 mi 的图像,mi 中的图像]

但是这两种方法都不如使用itertools.chain:

<预><代码>>>>从 itertools 导入链>>>列表(链(*list_of_menuitems))

正如@cdleary 指出的那样,通过使用 chain.from_iterable 来避免 * 运算符魔术可能是更好的风格:

<预><代码>>>>chain = itertools.chain.from_iterable([[1,2],[3],[5,89],[],[6]])>>>打印(列表(链))>>>[1, 2, 3, 5, 89, 6]

解决方案

如果您只想迭代数据结构的扁平版本并且不需要可索引的序列,请考虑 itertools.chain 和公司.

<预><代码>>>>list_of_menuitems = [['image00', 'image01'], ['image10'], []]>>>导入迭代工具>>>chain = itertools.chain(*list_of_menuitems)>>>打印(列表(链))['image00', 'image01', 'image10']

它适用于任何可迭代的东西,其中应该包括 Django 的可迭代 QuerySets,这似乎是您在问题中使用的.

无论如何,这可能与 reduce 一样好,因为 reduce 将具有相同的开销,将项目复制到正在扩展的列表中.如果您在最后运行 list(chain)chain 只会产生这种(相同的)开销.

实际上,它的开销比问题提出的解决方案要少,因为当您使用临时列表扩展原始列表时,您会丢弃创建的临时列表.

作为 J.F.Sebastian 说 itertools.chain.from_iterable 避免了解包,你应该使用它来避免 * 魔法,但是 timeit 应用程序 显示的性能差异可以忽略不计.

Is there a simple way to flatten a list of iterables with a list comprehension, or failing that, what would you all consider to be the best way to flatten a shallow list like this, balancing performance and readability?

I tried to flatten such a list with a nested list comprehension, like this:

[image for image in menuitem for menuitem in list_of_menuitems]

But I get in trouble of the NameError variety there, because the name 'menuitem' is not defined. After googling and looking around on Stack Overflow, I got the desired results with a reduce statement:

reduce(list.__add__, map(lambda x: list(x), list_of_menuitems))

But this method is fairly unreadable because I need that list(x) call there because x is a Django QuerySet object.

Conclusion:

Thanks to everyone who contributed to this question. Here is a summary of what I learned. I'm also making this a community wiki in case others want to add to or correct these observations.

My original reduce statement is redundant and is better written this way:

>>> reduce(list.__add__, (list(mi) for mi in list_of_menuitems))

This is the correct syntax for a nested list comprehension (Brilliant summary dF!):

>>> [image for mi in list_of_menuitems for image in mi]

But neither of these methods are as efficient as using itertools.chain:

>>> from itertools import chain
>>> list(chain(*list_of_menuitems))

And as @cdleary notes, it's probably better style to avoid * operator magic by using chain.from_iterable like so:

>>> chain = itertools.chain.from_iterable([[1,2],[3],[5,89],[],[6]])
>>> print(list(chain))
>>> [1, 2, 3, 5, 89, 6]

解决方案

If you're just looking to iterate over a flattened version of the data structure and don't need an indexable sequence, consider itertools.chain and company.

>>> list_of_menuitems = [['image00', 'image01'], ['image10'], []]
>>> import itertools
>>> chain = itertools.chain(*list_of_menuitems)
>>> print(list(chain))
['image00', 'image01', 'image10']

It will work on anything that's iterable, which should include Django's iterable QuerySets, which it appears that you're using in the question.

Edit: This is probably as good as a reduce anyway, because reduce will have the same overhead copying the items into the list that's being extended. chain will only incur this (same) overhead if you run list(chain) at the end.

Meta-Edit: Actually, it's less overhead than the question's proposed solution, because you throw away the temporary lists you create when you extend the original with the temporary.

Edit: As J.F. Sebastian says itertools.chain.from_iterable avoids the unpacking and you should use that to avoid * magic, but the timeit app shows negligible performance difference.

这篇关于在 Python 中展平一个浅表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆