Python从列表中删除项目

4

我有一个以给定格式呈现的列表:

[['John', 'Smith'], ['Linus', 'Torvalds'], ['Bart', 'Simpson']]

在列表中有一些元素是 ['Linus Torvalds', ''] 这样的形式,我想把它们去掉。那为什么下面的代码没法去除它们呢?
for i in people:
    if(i[0] == '' or i[1] == ''):
        print people.pop(people.index(i))

我也尝试过 people.remove(i)。 - Diego Allen
3
你给的列表中没有任何一种情况,其中第一个或第二个元素是空字符串。 - Jeff Ames
当你想要处理索引时,可以使用类似于 for i, (first, last) in enumerate(people): 的语句,其中 i 将会是 0、1、2 等等。 - Chris Morgan
你想要做的事情,通过获取迭代器(iter(people))并仅在某些时候调用iterator.next()是完全可能的...但这很少是最佳解决方案。 - Chris Morgan
4个回答

10

你正在遍历列表的同时修改它,这是你问题的根源。一个有效的解决方法是

people[:] = [p for p in people if p[0] != '' and p[1] != '']

当使用这种方式时,将建立一个新的临时列表,其中仅包含您想要的元素,并在操作完成时将其分配给原始列表对象。


2
如果你想最终得到相同的列表对象,你可以用people[:] = [p for p in ...替换赋值语句,这样列表推导的结果就会被塞回原始列表中。 - SingleNegationElimination
@TokenMacGuy:说得好。已更新答案。 - 6502
1
嗯,现在没有人能看到旧的方式了。当您不需要保留列表对象标识时,可以将赋值替换为people = [p for p in ...,这样会更快一些,因为它避免了一些(但并不是非常多的)复制。 - SingleNegationElimination
原始代码试图使用'pop'更改对象,可能是因为其他人可以访问它; 从语义的角度来看,当前版本因此是对原始问题的更好答案。 - 6502
它可能更接近他最初的解决方案,但这并不意味着它是类似于问题的任何问题的最佳解决方案,即使对于这个特定的帖子也是如此。成功的Pythonista可以同时使用两种技术。 - SingleNegationElimination

4
如果您想“原地”调整列表大小,甚至可以使用people[:] = [p for p in people if all(p)]。这与删除不符合条件的元素并将结果分配回原始列表相同。请注意保留HTML标记。

3
您正在遍历列表时修改其长度,这会导致您跳过一些值。当您从列表中弹出一个项目时,以下是发生的情况(参考此回答):
[1, 2, 3, 4, 5, 6...]
 ^

初始时,这是列表的状态;现在假设移除了1并且循环进入列表的第二个项目:

[2, 3, 4, 5, 6...]
    ^

And so on.


1

在迭代列表时删除其中的元素是一个不好的想法。因此,可以尝试以下方法之一(另外,我认为您的条件不是您想要的 - 我已经修复了它):

L = [['John', 'Smith'], ['Linus', 'Torvalds'], ['Bart', 'Simpson']]
delete_these = []
for index, i in enumerate(L):
    if not i[-1].strip():
        delete_these.append(i)
for i in delete_these:
    L.pop(i)
    delete_these = map(lambda x: x-1, delete_these)

或者

L = [i for i in L if i[-1].strip()]

或者

answer = []
for i in L:
    if i[-1].strip():
        answer.append(i)

或者

i = 0
while i < len(L):
    if not L[i][-1].strip():
        L.pop(i)
    else:
        i += 1

希望这有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接