我想从此列表中获取唯一的Non-None元素:
L = [None, [None,None], [None, <__main__.Car object at 0x02A11550>], [None, None, None], None]
我试过
L = [x for x in L if x is not None]
但结果是
[[None, None], [None, <__main__.Car object at 0x02A11550>], [None, None, None]]
仅删除不在任何列表中的None。 有没有办法清理整个清单?所以输出是
<__main__.Car object at 0x02A11550>
答案 0 :(得分:3)
def flatten(lst):
for element in lst:
if hasattr(element,"__iter__"):
yield from flatten(element)
elif not element is None:
yield element
new_list = flatten(L)
我会先为你解决这个问题,首先从发电机开始。 yield
关键字是return
的姊妹,但功能却大不相同。两者都用于将函数中的值带入其调用范围,但yield
允许您之后跳回函数!例如,下面是一个生成器,它接受一个包含数字的列表,并为列表中的每个数字生成正方形。
def example_generator(number_list):
for number in number_list:
yield number**2
>>> gen = example_generator([1,2,3])
>>> type(gen)
<class 'generator'>
>>> next(gen) # next() is used to get the next value from an iterator
1
>>> next(gen)
4
>>> next(gen)
9
>>> next(gen)
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
next(gen)
StopIteration
然而,发电机是一次性使用的。如您所见,在我到达生成器的末尾之后,它抛出异常StopIteration
。如果我再次构建它并用循环遍历它,那么尝试再次运行它...
>>> gen = example_generator([1,2,3]) # remember this is a new generator, we JUST made it
>>> for item in gen:
... print(item)
1
4
9
>>> for item in gen:
... print(item)
>>>
第二次没有做任何事情。发电机已耗尽。这是缺点 - 好处是使用生成器代替列表通常更快,内存效率更高。
yield
还允许您使用其他关键字:from
。这就是我在嵌套列表中所做的事情(hasattr(element,"__iter__")
只是意味着该元素具有属性.__iter__
,这意味着它可以在使用for
循环之类的东西时进行迭代。你给yield from
另一个生成器,它依次从THAT生成器中生成每个元素。例如:
def flatten_lite(lst):
for element in lst:
if type(element) is list: # more readable, IMO
yield from flatten_lite(element)
else:
yield element
a = flatten_lite([1,2,3,[4,5,6,[7],8],9])
以下是它的作用:
for element in [1,2,3,[4,5,6,[7],8],9]:
# element == 1
if element is of type list: # it's not, skip this
else: yield element # which is 1
:: NEXT ITERATION ::
# element == 2, same as before
:: NEXT ITERATION ::
# element == 3, same as before
:: NEXT ITERATION ::
# element == [4,5,6,[7],8]
if element is of type list: # it is!!
yield from flatten_lite([4,5,6,[7],8])
:: STOP EXECUTION UNTIL WE GET A VALUE FROM THAT NEW GENERATOR ::
>>> NEW GENERATOR
for element in [4,5,6,[7],8]:
# element is 4
yield 4
:: THE OUTER GENERATOR YIELDS 4 ::
:: NEXT ITERATION ::
# element is 5
yield 5
:: THE OUTER GENERATOR YIELDS 4 ::
:: NEXT ITERATION ::
# element is 6
yield 6
:: THE OUTER GENERATOR YIELDS 4 ::
:: NEXT ITERATION ::
# element is [7]
if element is of type list # [7] is a list!
yield from flatten_lite([7])
:: STOP EXECUTION UNTIL WE GET A VALUE FROM THAT NEW GENERATOR ::
# etc etc
所以基本上上面的代码(伪代码):
flatten is a function that accepts parameter: lst
for each element in lst:
if element can be iterated on:
yield every element in turn from the generator created
by this function called on the element instead of the
main list
if it's not, and isn't None:
yield element
当你调用它时,它会构建一个可以迭代的生成器。要将其变为正式列表,您必须执行list(flatten(L))
,但在大多数情况下,您不需要这样做。
有没有更明确的?
答案 1 :(得分:1)
另一种稍微模块化的方法:
def flatten(l):
""" http://stackoverflow.com/questions/2158395/flatten-an-irregular-list-of-lists-in-python/2158532#2158532 """
for el in l:
if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
for sub in flatten(el):
yield sub
else:
yield el
filter(None,flatten(L)) #wrap with `list` in python 3.x
通用flatten
功能是您应该保留在工具箱中的功能,因为(到目前为止)它不是您可以在标准库中找到的东西,偶尔会出现。
答案 2 :(得分:0)
只是为了好玩,怎么样:
from itertools import chain, ifilterfalse
result = list(ifilterfalse(lambda x: x is None, chain(*[x for x in L if x is not None])))
这将返回仅包含list
元素的Car
。它会推广使用任何非list
元素返回None
。
在Python 3.x中,我认为您将ifilterfalse
换成filterfalse
,它的工作方式相同。
chain()
旨在展开list
list
次迭代。 ifilterfalse
可以直接在chain
返回。 ifilterfalse
删除与lambda
函数指定的谓词匹配的元素。
请注意,如果L
中有字符串,chain()
基本上会将字符串分解为单个元素。如果这对您来说是个问题,请参阅此其他SO post。
另一种避免基本级别不可迭代问题的实现:
result = list(ifilterfalse(lambda x: x is None, chain(*[x if hasattr(x, '__iter__') else [x] for x in L if x is not None])))
我告诉我这可能不适用于Python 3,因为str
在那里实现的方式。无论如何,我只发布这些想法,以便您了解itertools
下Python标准库中已有的功能。玩得开心学习Python!