for tup in somelist:
if determine(tup):
code_to_remove_tup
我应该使用什么替换code_to_remove_tup
?我无法弄清楚如何以这种方式删除项目。
这个答案最初是回答一个已被标记为重复的问题而撰写的: 从Python中删除列表中的坐标
你的代码有两个问题:
1) 当使用remove()函数时,你试图删除整数,而你需要删除元组。
2) for循环将跳过你列表中的某些项。
让我们来看一下当我们执行你的代码时会发生什么:
>>> L1 = [(1,2), (5,6), (-1,-2), (1,-2)]
>>> for (a,b) in L1:
... if a < 0 or b < 0:
... L1.remove(a,b)
...
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
TypeError: remove() takes exactly one argument (2 given)
第一个问题是你将'a'和'b'同时传递给remove()方法,但remove()方法只接受一个参数。所以我们该如何让remove()方法正确地处理你的列表呢?我们需要弄清楚列表中每个元素是什么。在这种情况下,每个元素都是一个元组。为了看到这一点,让我们访问列表中的一个元素(索引从0开始):>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'tuple'>
啊哈!L1的每个元素实际上都是一个元组。所以这就是我们需要传递给remove()的东西。在Python中,元组非常容易,它们只是将值括在括号内。"a,b"不是元组,但"(a,b)"是一个元组。所以我们修改你的代码并再次运行:
# The remove line now includes an extra "()" to make a tuple out of "a,b"
L1.remove((a,b))
这段代码没有任何错误,但让我们看一下它输出的列表:
L1 is now: [(1, 2), (5, 6), (1, -2)]
为什么你的列表中仍然包含(1,-2)?原来是在使用循环遍历时修改列表是一个非常不好的想法,需要特别小心。(1,-2) 保留在列表中的原因是在for循环迭代之间每个项目的位置发生了变化。让我们看一下如果我们给上面的代码提供一个更长的列表会发生什么:
L1 = [(1,2),(5,6),(-1,-2),(1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
### Outputs:
L1 is now: [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]
从那个结果可以推断出,每当条件语句评估为true并且列表项被删除时,循环的下一次迭代将跳过对列表中下一项的评估,因为其值现在位于不同的索引位置。
最直观的解决方法是复制列表,然后迭代原始列表并仅修改副本。您可以尝试这样做:
L2 = L1
for (a,b) in L1:
if a < 0 or b < 0 :
L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
print L2 is L1
del L1
L1 = L2; del L2
print ("L1 is now: ", L1)
然而,输出结果将与之前相同:
'L1 is now: ', [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]
这是因为当我们创建 L2 时,Python 实际上并没有创建一个新对象。相反,它仅仅将 L2 引用到与 L1 相同的对象。我们可以使用 'is' 进行验证,这与仅仅“相等”(==)不同。
>>> L2=L1
>>> L1 is L2
True
我们可以使用copy.copy()创建真正的副本,然后一切都按照预期工作:
import copy
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
L2 = copy.copy(L1)
for (a,b) in L1:
if a < 0 or b < 0 :
L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
del L1
L1 = L2; del L2
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]
最后,有一个比完全复制L1更为简洁的解决方案:reversed()函数:
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
for (a,b) in reversed(L1):
if a < 0 or b < 0 :
L1.remove((a,b))
print ("L1 is now: ", L1)
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]
很遗憾,我无法充分描述reversed()的工作原理。当一个列表被传递给它时,它返回一个'listreverseiterator'对象。出于实际目的,您可以将其视为创建其参数的反向副本。这是我推荐的解决方案。
i = 0
length = len(list1)
while i < length:
if condition:
list1.remove(list1[i])
i -= 1
length -= 1
i += 1
filter
。然而,在只有在迭代过程中仅删除一个元素时,才可以安全地从正在迭代的序列中删除元素。这可以通过使用 return
或 break
来确保。例如:for i, item in enumerate(lst):
if item % 4 == 0:
foo(item)
del lst[i]
break
当你需要在符合某个条件的列表中对第一个元素进行带有副作用的操作,然后立即将该元素从列表中删除时,使用生成器表达式往往比列表推导式更易于理解。
如果您不仅想删除一些东西,还想在单个循环中对所有元素进行操作,那么有一个可能的解决方案:
alist = ['good', 'bad', 'good', 'bad', 'good']
i = 0
for x in alist[:]:
if x == 'bad':
alist.pop(i)
i -= 1
# do something cool with x or just print x
print(x)
i += 1
alist[:]
)。而且,由于你可能正在做一些花哨的事情,它实际上具有使用案例。好的修订是好的。顶你一个赞。 - Beefster一个for循环将会遍历一个索引...
假设你有一个列表,
[5, 7, 13, 29, 65, 91]
lis
的列表变量。你使用它来删除...。lis = [5, 7, 13, 29, 35, 65, 91]
0 1 2 3 4 5 6
lis.remove(y)
lis = [5, 7, 13, 29, 65, 91]
0 1 2 3 4 5
因此第四次迭代完成后指针移动到第五个...
这就是为什么你的循环不包括65,因为它已经移动到了前一个索引。
所以你不应该将列表引用到另一个变量中,该变量仍然引用原始列表而不是副本。
ite = lis # Don’t do it will reference instead copy
现在,您需要使用list[::]
复制该列表。
接下来,您将会得到:
[5, 7, 13, 29]
lis = [5, 7, 13, 29, 35, 65, 91]
not_primes = [35,65]
for item in not_primes: if item in lis: lis.remove(item)
我自己也遇到了这个问题,在这里讨论过:https://stackoverflow.com/q/72478091/1973308 - Hank Lenzi如果您在迭代期间需要执行其他操作,获取索引(这可以确保您能够引用它,例如如果您有一个字典列表)和实际的列表项内容可能是很好的选择。
inlist = [{'field1':10, 'field2':20}, {'field1':30, 'field2':15}]
for idx, i in enumerate(inlist):
do some stuff with i['field1']
if somecondition:
xlist.append(idx)
for i in reversed(xlist): del inlist[i]
enumerate
可以同时让你访问元素和索引。使用 reversed
是为了防止之后要删除的索引位置变化。
```
k = range(5)
v = ['a','b','c','d','e']
d = {key:val for key,val in zip(k, v)}
print d
for i in range(5):
print d[i]
d.pop(i)
print d
```
list_len = len(some_list)
for i in range(list_len):
reverse_i = list_len - 1 - i
cur = some_list[reverse_i]
# some logic with cur element
if some_condition:
some_list.pop(reverse_i)
这样索引就会对齐,并且不会受到列表更新的影响(无论您是否弹出当前元素)。
reversed(list(enumerate(some_list)))
比自己计算索引更简单。 - Mark Amery最有效的方法是使用列表推导式,许多人展示了他们的案例,当然,通过filter
获取iterator
也是一个不错的方法。
filter
接收一个函数和一个序列。filter
依次将传递的函数应用于每个元素,然后根据函数返回值是否为True
或False
来决定是否保留或丢弃元素。
下面是一个示例(从元组中获取奇数):
list(filter(lambda x:x%2==1, (1, 2, 4, 5, 6, 9, 10, 15)))
# result: [1, 5, 9, 15]