PYTHON从嵌套列表中删除元素
我有一个这样的数组PYTHON从嵌套列表中删除元素,python,list,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) 但这是行不通的 结果应该是: [['3
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']]
您从错误的列表中删除。尝试设置。删除(项目) 但是要注意,只有当数据是唯一的时,这才有效,也就是说,对于条件只有一个匹配项,因为在循环内部删除时跳过了索引
Martijn提供了一个完整的python解决方案。使用嵌套列表理解,保留元素:
dataSet = [[i for i in nested if i != '311472'] for nested in dataSet]
演示:
您的错误是从数据集
中删除了项
,但即使您从集合
中删除了元素,您最终也会在迭代时修改列表,这意味着进一步的迭代将跳过元素:
>>> 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的所有内容都向下移动了一个点。如果您想修改列表,可以使用以下代码(我相信这是您最初的计划):
如果在一个
集合中有许多重复的“311472”
(顺便说一句,这不是列表的好名称,并且隐藏了相同名称的内置项),这可能会很慢。我们讨论的是删除给定值的每一次出现<代码>列表。删除
已执行扫描,因此我们可以在知道是否可以成功之前调用它:
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]
事实上,这让我非常恼火,以至于写了另一个就地删除变体。这是一种更具python风格但仍然浪费的变体:
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:]
没有例外,只有一次通过列表,但是一些笨拙的索引计算。不过,这可能会尽可能提高内存效率 我们必须从列表中删除'311472' 所以试着从列表中删除列表[list.remove] 即 a=['387230']、['296163']、['323434'、'311472'、'323412'、'166282']、['410119'] 对于a中的ina: 对于ina中的ina: 如果inaina==“311472”: ina.删除(“311472”)
打印一张这不起作用;在适当的位置修改序列将导致遗漏元素。这是一个很好的观点。我仍然认为主要的问题是OP试图从错误的列表中删除。当然,但也许他先尝试了,但对于更复杂的示例,这并没有像预期的那样起作用?这将在整个列表中循环数次以扫描元素;对于测试中的
和调用.remove()
都会导致性能下降。对于列表中的每一个新元素,您都要加倍努力。@MartijnPieters:这有点太过分了<如果不包含“311472”
,则
中的code>将仅扫描整个列表(集
),在这种情况下,甚至不会调用删除
。我认为元素的数量不存在二次行为。当然,如果列表仅(或主要)由“311472”
元素组成,则会出现二次行为(但不一定是因为扫描,而是因为复制)。我指出,这将是缓慢的多次重复。(对于OP给出的示例,此解决方案比您的解决方案快得多。)在最坏的情况下,长元素列表的后半部分只包含大量扫描,每次扫描两次。由于.remove()
已经扫描,至少Yann的解决方案要好一点。:-)如果只有那个条目,那么每次扫描都很便宜,但每次删除都会花费不必要的代价,因为它会不断重新排列列表中的引用。这种情况最有利于重建解决方案。。后半个病例使扫描费用昂贵,因此可能更糟。抱歉读得太草率了。@MartijnPieters:我仍然不确定我的答案遗漏了什么或错了什么。在某些情况下,它可能很慢,就像我写的那样;您认为应该进一步开发吗?您知道数据集中'311472'
的数量吗?这不是一个集合。集合定义为集合(迭代器)
lst[:]=[item for item in lst if item!=key]
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:]