PYTHON从嵌套列表中删除元素

时间:2013-10-07 08:53:45

标签: python list

我有一个像这样的数组

dataSet = [['387230'], ['296163'], ['323434', '311472', '323412', '166282'], ['410119']]

我想删除元素'311472',但不知道如何。我试过了

for set in dataSet:
    for item in set:
        if item=="311472":
            dataSet.remove(item)

但这不起作用

结果应为:

[['387230'], ['296163'], ['323434', '323412', '166282'], ['410119']]

5 个答案:

答案 0 :(得分:9)

使用嵌套列表解析,保留元素:

dataSet = [[i for i in nested if i != '311472'] for nested in dataSet]

演示:

>>> [[i for i in nested if i != '311472'] for nested in dataSet]
[['387230'], ['296163'], ['323434', '323412', '166282'], ['410119']]

您的错误是从item删除dataSet,但即使您从set删除了元素,您最终会在迭代时修改列表,这意味着进一步的迭代将跳过元素:

>>> lst = ['323434', '311472', '311472', '323412', '166282']
>>> for i in lst:
...     if i == '311472':
...         lst.remove(i)
... 
>>> lst
['323434', '311472', '323412', '166282']

这是因为列表迭代器移动到下一个索引,而不管以后添加或删除列表;当删除索引1处的第一个'311472'时,循环移动到列表中的索引2,其中过去索引1的所有内容都向下移动了一个点。

答案 1 :(得分:4)

您从错误的列表中删除。请改为set.remove(item)

请注意,这只有在数据是唯一的情况下才有效,即您只有一个条件匹配,因为当您在循环中移除时跳过索引。

Martijn提供完整的pythonic解决方案。

答案 2 :(得分:0)

如果您想要就地修改列表,可以使用以下代码(我认为这与您的原始计划一致):

for set in dataSet:
    while "311472" in set:
        set.remove("311472")

如果单个"311472"中有多个多次重复set(顺便说一句,这不是列表的好名称,并且隐藏了相同名称的内置),这可能会很慢。

答案 3 :(得分:0)

我们正在谈论删除给定值的每个出现。 list.remove已经进行了扫描,因此我们可以在知道它是否成功之前调用它:

for sublist in dataSet:
    while True:  # list.remove only removes the first occurence
        try:
            sublist.remove("311472")
        except ValueError, e:
            break  # stop removing, there's no such item in this sublist

如果包含已删除值的列表很大,这自然不是很有效,因为我们重复删除。对于列表理解解决方案Martijn Pieters建议,如果不包含删除值的列表很大(因为它们被重建),瓶颈就是。

第三种解决方案是扫描列表并移动条目,将条目的重新分配保存到最后:

def removeAll(lst, item):
    "Like list.remove(), but removes all matching items, without raising ValueError"
    outend=0
    instart=0
    while True:
        try:
            inend=lst.index(item, instart)
        except ValueError, e:
            # We've reached the end of the list
            if outend!=instart:
                # Place remaining items in the correct place and truncate
                lst[outend:]=lst[instart:]
            return

        size=inend-instart
        # Move non-matching items down to replace matching ones
        if size and outend!=instart:
            lst[outend:outend+size]=lst[instart:inend]
        outend+=size
        instart=inend+1  # Skip over the matching entry

过早优化的相当可怕的例子 - 这需要花费太长时间来编写和调试,并且与普通重建相比只有微小的收益(可能根本没有,取决于程序的其余部分)。实际上,想到它,我认为没有任何收获,因为列表切片本身会创建我们想要保留的部分的子索引。我想如果你要删除的元素率很高,非常长列表,而真的希望就地完成更改。在重建解决方案之后更改原始列表是微不足道的:

lst[:]=[item for item in lst if item!=key]

实际上,这只是让我误以为可以编写另一个就地删除变体。这是一种更多的Pythonic,但仍然是浪费的变种:

def removeAll2(lst, remove):
    rem=0
    for idx,value in enumerate(lst):
        if value==remove:
            rem+=1
        elif rem:
            lst[idx-rem]=value
    if rem:
        del lst[-rem:]

没有例外,只有一次通过列表,但有些笨拙的索引计算。不过,这很可能是因为内存效率高。

答案 4 :(得分:0)

我们必须从列表中删除“311472”

所以尝试从该列表中删除列表[list.remove] 即,

a = [['387230'],['296163'],['323434','311472','323412','166282'],['410119']]

for in in:     in inaina in ina:         如果inaina ==“311472”:           ina.remove( “311472”) 打印