在Python中展平浅表列表 有没有一种简单的方法可以用列表理解来平移一个迭代列表,或者失败了,你认为什么是最好的方法来平淡这样一个浅薄的列表,平衡性能和可读性?
我试图用嵌套的列表理解将这样的列表展平,如下所示:在Python中展平浅表列表 有没有一种简单的方法可以用列表理解来平移一个迭代列表,或者失败了,你认为什么是最好的方法来平淡这样一个浅薄的列表,平衡性能和可读性?,python,list-comprehension,Python,List Comprehension,我试图用嵌套的列表理解将这样的列表展平,如下所示: [image for image in menuitem for menuitem in list_of_menuitems] 但是我遇到了名称错误的麻烦,因为名称“menuitem”没有定义。在谷歌搜索和查看堆栈溢出后,我使用reduce语句得到了想要的结果: reduce(list.__add__, map(lambda x: list(x), list_of_menuitems)) 但是这个方法相当不可读,因为我需要在那里调用list
[image for image in menuitem for menuitem in list_of_menuitems]
但是我遇到了名称错误
的麻烦,因为名称“menuitem”没有定义
。在谷歌搜索和查看堆栈溢出后,我使用reduce
语句得到了想要的结果:
reduce(list.__add__, map(lambda x: list(x), list_of_menuitems))
但是这个方法相当不可读,因为我需要在那里调用list(x)
,因为x是DjangoQuerySet
对象
结论:
感谢所有对此问题做出贡献的人。以下是我所学知识的总结。我还将此作为一个社区wiki,以防其他人想要添加或更正这些观察结果
我最初的reduce语句是多余的,最好这样写:
>>> reduce(list.__add__, (list(mi) for mi in list_of_menuitems))
这是嵌套列表理解的正确语法(精彩摘要!):
但这两种方法都不如使用itertools.chain有效:
>>> from itertools import chain
>>> list(chain(*list_of_menuitems))
正如@cdleary所指出的,使用
链来避免*操作符的魔力可能是更好的方式
>>> chain = itertools.chain.from_iterable([[1,2],[3],[5,89],[],[6]])
>>> print(list(chain))
>>> [1, 2, 3, 5, 89, 6]
在我的头顶上,你可以消除lambda:
reduce(list.__add__, map(list, [mi.image_set.all() for mi in list_of_menuitems]))
或者甚至取消地图,因为您已经有了一个列表:
reduce(list.__add__, [list(mi.image_set.all()) for mi in list_of_menuitems])
您也可以将其表示为列表的总和:
sum([list(mi.image_set.all()) for mi in list_of_menuitems], [])
在我的头顶上,你可以消除lambda:
reduce(list.__add__, map(list, [mi.image_set.all() for mi in list_of_menuitems]))
或者甚至取消地图,因为您已经有了一个列表:
reduce(list.__add__, [list(mi.image_set.all()) for mi in list_of_menuitems])
您也可以将其表示为列表的总和:
sum([list(mi.image_set.all()) for mi in list_of_menuitems], [])
那么:
from operator import add
reduce(add, map(lambda x: list(x.image_set.all()), [mi for mi in list_of_menuitems]))
但是,Guido建议不要在一行代码中执行太多操作,因为这样会降低可读性。通过在一行中执行您想要的操作,与在多行中执行您想要的操作相比,性能增益最小(如果有的话)。关于:
from operator import add
reduce(add, map(lambda x: list(x.image_set.all()), [mi for mi in list_of_menuitems]))
但是,Guido建议不要在一行代码中执行太多操作,因为这样会降低可读性。在单行与多行中执行所需的性能最小,如果有的话, 如果您只想遍历数据结构的扁平化版本,不需要索引序列,请考虑./P>
它可以处理任何iterable,其中应该包括Django的iterableQuerySet
s,这似乎是您在问题中使用的
Edit:无论如何,这可能与reduce一样好,因为reduce将项目复制到正在扩展的列表中的开销相同<代码>链
只有在最后运行列表(链)
时才会产生此(相同)开销
元编辑:实际上,它比问题的建议解决方案的开销要小,因为当您使用临时列表扩展原始列表时,您会丢弃创建的临时列表
<> > >编辑:<>代码> ItRealStudio.Cu链.FaseRealEdaby避免拆包,你应该使用它来避免<代码> */Cuth-FooT,但显示性能差异微乎其微。 < P>如果你只想遍历数据结构的扁平化版本,不需要索引序列,请考虑./P> 它可以处理任何iterable,其中应该包括Django的iterable
QuerySet
s,这似乎是您在问题中使用的
Edit:无论如何,这可能与reduce一样好,因为reduce将项目复制到正在扩展的列表中的开销相同<代码>链只有在最后运行列表(链)
时才会产生此(相同)开销
元编辑:实际上,它比问题的建议解决方案的开销要小,因为当您使用临时列表扩展原始列表时,您会丢弃创建的临时列表
编辑:作为
itertools.chain.from\u iterable
避免解包,您应该使用它来避免*
魔术,但显示的性能差异可以忽略不计。以下是使用列表理解的正确解决方案(在问题中它们是落后的):
在你的情况下是这样的
[image for menuitem in list_of_menuitems for image in menuitem.image_set.all()]
或者你可以使用join
并说
join(menuitem.image_set.all() for menuitem in list_of_menuitems)
在任何一种情况下,问题的症结都是循环的嵌套。下面是使用列表理解的正确解决方案(在问题中它们是向后的): 在你的情况下是这样的
[image for menuitem in list_of_menuitems for image in menuitem.image_set.all()]
或者你可以使用join
并说
join(menuitem.image_set.all() for menuitem in list_of_menuitems)
在这两种情况下,gotcha都是for
循环的嵌套。你几乎拥有了它!方法是将for
语句的顺序与常规嵌套for
语句的顺序相同
因此,
for inner_list in outer_list:
for item in inner_list:
...
对应于
[... for inner_list in outer_list for item in inner_list]
所以你想要
[image for menuitem in list_of_menuitems for image in menuitem]
你几乎成功了!方法是将for
语句的顺序与常规嵌套for
语句的顺序相同
因此,
for inner_list in outer_list:
for item in inner_list:
...
对应于
[... for inner_list in outer_list for item in inner_list]
所以你想要
[image for menuitem in list_of_menuitems for image in menuitem]
绩效结果。修订
import itertools
def itertools_flatten( aList ):
return list( itertools.chain(*aList) )
from operator import add
def reduce_flatten1( aList ):
return reduce(add, map(lambda x: list(x), [mi for mi in aList]))
def reduce_flatten2( aList ):
return reduce(list.__add__, map(list, aList))
def comprehension_flatten( aList ):
return list(y for x in aList for y in x)
我将30个项目的两级列表展平1000次
itertools_flatten 0.00554
comprehension_flatten 0.00815
reduce_flatten2 0.01103
reduce_flatten1 0.01404
减少总是一个糟糕的选择。性能结果。修订
import itertools
def itertools_flatten( aList ):
return list( itertools.chain(*aList) )
from operator import add
def reduce_flatten1( aList ):
return reduce(add, map(lambda x: list(x), [mi for mi in aList]))
def reduce_flatten2( aList ):
return reduce(list.__add__, map(list, aList))
def comprehension_flatten( aList ):
return list(y for x in aList for y in x)
我将30个项目的两级列表展平1000次
itertools_flatten 0.00554
comprehension_flatten 0.00815
reduce_flatten2 0.01103
reduce_flatten1 0.01404
Reduce始终是一个糟糕的选择。此解决方案适用于任意嵌套深度,而不仅仅是一些(所有?)其他解决方案限制的“列表”深度:
def flatten(x):
result = []
for el in x:
if hasattr(el, "__iter__") and not isinstance(el, basestring):
result.extend(flatten(el))
else:
result.append(el)
return result
递归允许任意深度嵌套-当然,直到达到最大递归深度…此解决方案适用于任意嵌套深度-而不仅仅是一些(所有?)其他解决方案限制的“列表”深度:
def flatten(x):
result = []
for el in x:
if hasattr(el, "__iter__") and not isinstance(el, basestring):
result.extend(flatten(el))
else:
result.append(el)
return result
它是允许任意深度嵌套的递归-当然,直到达到最大递归深度…:你启发我写了一篇tim
list_of_list = [range(10)]*1000
%timeit flat_list=[]; map(flat_list.extend, list_of_list)
#10000 loops, best of 3: 119 µs per loop
%timeit flat_list=list(itertools.chain.from_iterable(list_of_list))
#1000 loops, best of 3: 210 µs per loop
%timeit flat_list=[i for sublist in list_of_list for i in sublist]
#1000 loops, best of 3: 525 µs per loop
%timeit flat_list=reduce(list.__add__,list_of_list)
#100 loops, best of 3: 18.1 ms per loop
list_of_list = [range(1000)]*10
%timeit flat_list=[]; map(flat_list.extend, list_of_list)
#10000 loops, best of 3: 60.7 µs per loop
%timeit flat_list=list(itertools.chain.from_iterable(list_of_list))
#10000 loops, best of 3: 176 µs per loop
class SquaredRange(object):
def __init__(self, n):
self.range = range(n)
def __iter__(self):
for i in self.range:
yield i**2
list_of_list = [SquaredRange(5)]*3
flat_list = []
map(flat_list.extend, list_of_list)
print flat_list
#[0, 1, 4, 9, 16, 0, 1, 4, 9, 16, 0, 1, 4, 9, 16]
l = [['image00', 'image01'], ['image10'], []]
print sum(l,[]) # prints ['image00', 'image01', 'image10']
>>> list2d = ((1,2,3),(4,5,6), (7,), (8,9))
>>> reduce(operator.concat, list2d)
(1, 2, 3, 4, 5, 6, 7, 8, 9)
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> reduce(operator.concat, list2d)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list2d = [[1,2,3],[4,5,6], [7], [8,9]]
>>> %timeit list(itertools.chain.from_iterable(list2d))
1000000 loops, best of 3: 1.36 µs per loop
>>> list2d = ((1,2,3),(4,5,6), (7,), (8,9))
>>> %timeit reduce(operator.concat, list2d)
1000000 loops, best of 3: 492 ns per loop
>>> flattener = re.compile("\'.*?\'")
>>> flattener
<_sre.SRE_Pattern object at 0x10d439ca8>
>>> stred = str(in_list)
>>> outed = flattener.findall(stred)
import collections
def flatten(o, flatten_condition=lambda i: isinstance(i,
collections.Iterable) and not isinstance(i, str)):
result = []
for i in o:
if flatten_condition(i):
result.extend(flatten(i, flatten_condition))
else:
result.append(i)
return result
def flat_list(list_to_flat):
if not isinstance(list_to_flat, list):
yield list_to_flat
else:
for item in list_to_flat:
yield from flat_list(item)
>>> a = [1, [2, 3], [1, [2, 3, [1, [2, 3]]]]]
>>> print(list(flat_list(a)))
[1, 2, 3, 1, 2, 3, 1, 2, 3]
a = [[1, 2, 3], [4, 5, 6]
b = [i[x] for i in a for x in range(len(i))]
print b
[1, 2, 3, 4, 5, 6]
import numpy as np
print np.concatenate([[1,2],[3],[5,89],[],[6]])
# array([ 1., 2., 3., 5., 89., 6.])
print list(np.concatenate([[1,2],[3],[5,89],[],[6]]))
# [ 1., 2., 3., 5., 89., 6.]
import morph
list = [[1,2],[3],[5,89],[],[6]]
flattened_list = morph.flatten(list) # returns [1, 2, 3, 5, 89, 6]
def is_iterable(item):
return isinstance(item, list) or isinstance(item, tuple)
def flatten(items):
for i in items:
if is_iterable(item):
for m in flatten(i):
yield m
else:
yield i
print list(flatten2([1.0, 2, 'a', (4,), ((6,), (8,)), (((8,),(9,)), ((12,),(10)))]))