如何從Python的列表中刪除所有非元素

2024-04-27 03:47:37 发布

您现在位置:Python中文网/ 问答频道 /正文

我想从这个列表中得到唯一的非None元素:

L = [None, [None,None], [None, <__main__.Car object at 0x02A11550>], [None, None, None], None]

我试过了

^{pr2}$

但结果是

[[None, None], [None, <__main__.Car object at 0x02A11550>], [None, None, None]]

只删除不在任何列表中的“无”。 有没有办法把整个名单都清理干净?所以输出是

<__main__.Car object at 0x02A11550>

Tags: none元素列表objectmaincarat名单
3条回答

另一种稍微模块化的方法:

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函数应该保存在工具箱中,因为(到目前为止)在标准库中找不到它,而且它偶尔会出现。在

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允许您以后跳回函数中!例如,下面是一个生成器,它接受一个充满数字的列表,并为列表中的每个数字生成正方形。在

^{pr2}$

不过,发电机是一次性的。如您所见,在我到达生成器的末尾之后,它抛出了一个异常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另一个生成器,它依次从该生成器生成每个元素。例如:

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)),但在大多数情况下,您不需要这样做。在

清楚了吗?在

只是为了好玩,不如:

from itertools import chain, ifilterfalse
result = list(ifilterfalse(lambda x: x is None, chain(*[x for x in L if x is not None])))

这将返回一个只有Car元素的list。它将泛化为返回带有任何非None元素的list。在

在python3.x中,我认为您可以将ifilterfalse替换为{},并且它的工作原理是一样的。在

chain()被设计成使list的一个list变平以进行迭代。ifilterfalse可以直接在返回的{}上工作。ifilterfalse删除与lambda函数指定的谓词匹配的元素。在

注意,如果在L中有字符串,chain()实际上将把字符串分解成单独的元素。如果这对您来说是个问题,请参阅另一个SO post。在

另一种避免了基本级别不可移植问题的实现:

^{pr2}$

我被告知这在Python3中可能行不通,因为str是如何实现的。无论如何,我只是发布这些想法,这样您就可以了解到Python标准库中itertools下已经提供的功能。学习Python愉快!在

相关问题 更多 >