Python 3 : Removing list item with for loop, 这是正确的方法吗?

标签 python list python-3.x for-loop

<分区>

我仍在学习 python 的基础知识,我刚刚花了一段时间阅读如何在 python 中从 for 循环中的列表中删除一个项目。我读过的所有内容都暗示了执行此操作的复杂方法,并且他们说您无法在迭代时从列表中删除项目。但是......这似乎有效:

class Object():
    def __init__(self):
        self.y = 0

object_list = [Object(), Object(), Object()]

for thing in object_list:
    thing.y += 1
    if thing.y > 10:
        object_list.remove(thing)

为什么这行得通,而其他人却说行不通并编写了复杂的解决方法?是因为不允许在 Python 2 中执行此操作但可以在 Python 3 中执行此操作吗?

这是正确的方法吗?它会按我想要的那样工作还是容易出现错误?如果我打算删除项目,是否建议以相反的顺序遍历列表?

很抱歉,如果之前已经回答过这个问题,但是很难知道哪些资源指的是什么,因为它们都在标签中说“python”(至少,我一直在阅读的那些,也许那是因为所有的我读过的是 python 2?)

谢谢!

编辑:

抱歉,有几个复制和粘贴错误...我已修复...

编辑:

我一直在观看 Raymond Hettinger 的另一个视频...他提到了一种在使用 dict.keys() 迭代字典的同时从字典中删除项目的方法。像这样的东西:

d = {'text': 'moreText', 'other': 'otherText', 'blah': 'moreBlah'}

for k in d.keys():
    if k.startswith('o'):
        del d[k]

显然,使用键可以在迭代时安全地删除项目。列表有等价物吗?如果有的话,我可以向后遍历列表并安全地删除项目

最佳答案

这里有一些例子

def example1(lst):
    for item in lst:
        if item < 4:
            lst.remove(item) 
    return lst

def example2(lst):
    for item in lst[:]:
        if item < 4:
            lst.remove(item)       
    return lst

def example3(lst):
    i = 0
    while i < len(lst):
        if lst[i] < 4:
            lst.pop(i)
        else:
            i += 1
    return lst

def example4(lst):
    return [item for item in lst if not item < 4]

def example5(lst):
    for item in reversed(lst):
        if item < 4:
            lst.remove(item)
    return lst

def example6(lst):
    for i, item in reversed(list(enumerate(lst))):
        if item < 4:
            lst.pop(i)
    return lst

def example7(lst):
    size = len(lst) - 1
    for i, item in enumerate(reversed(lst)):
        if item < 4:
            lst.pop(size - i)
    return lst

def example8(lst):
    return list(filter(lambda item: not item < 4, lst))

import itertools
def example9(lst):
    return list(itertools.filterfalse(lambda item: item < 4, lst))

# Output
>>> lst = [1, 1, 2, 3, 2, 3, 4, 5, 6, 6]
>>> example1(lst[:])
[1, 3, 3, 4, 5, 6, 6]
>>> example2(lst[:])
[4, 5, 6, 6]
>>> example3(lst[:])
[4, 5, 6, 6]
>>> example4(lst[:])
[4, 5, 6, 6]
>>> example5(lst[:])
[4, 5, 6, 6]
>>> example6(lst[:])
[4, 5, 6, 6]
>>> example7(lst[:])
[4, 5, 6, 6]
>>> example8(lst[:])
[4, 5, 6, 6]
>>> example9(lst[:])
[4, 5, 6, 6]

示例 1 此示例涉及遍历列表并从中删除值。这样做的问题是,您在遍历列表时正在修改列表,因此您的列表在迭代过程中会发生变化,因此某些元素会被跳过。

示例 2 这里我们迭代列表的浅拷贝而不是列表本身。这样做的问题是,如果您的列表很大,那么这样做的成本可能很高。

示例 3 以下是使用 pop 而不是 remove 的示例,remove 的问题在于它会删除它从列表。这通常不会有问题,除非您有相等的对象。 (参见示例 10)

示例 4 我们没有在此处修改列表,而是使用仅允许指定值的列表理解创建一个新列表。

示例 5 这是一个反向遍历列表的示例,不同之处在于我们使用内置的 reversed 函数来应用 for 循环,而不是带有计数器的 while 循环。

示例 6 类似的示例使用 pop 代替。

示例 7 使用 pop 的更好示例,因为我们不必转换回列表即可使用 reversed 函数。

示例 8 使用内置过滤器方法删除指定值的示例。

示例 9 使用 itertools

中的 filerfalse 方法的类似示例
class Example(object):
    ID = 0
    def __init__(self, x):
        self._x = x
        self._id = str(Example.ID)
        Example.ID += 1

    def __eq__(self, other):
        return self._x == other._x

    def __repr__(self):
        return 'Example({})'.format(self._id)

def example10():
    lst = [Example(5), Example(5)]
    print(lst)
    lst.remove(lst[1])
    return lst

#Output
>>> example10()
[Example(0), Example(1)]
[Example(1)]

示例 10 这里我们创建了两个具有相同值的 Example 对象,并且通过相等方法它们是相等的。 ID 变量可以帮助我们区分两者。现在我们已经指定要从列表中删除第二个对象,但是因为两者相等,所以实际上删除的是第一个对象。

时间 这些是非常艰难的时期,可能会因您的设备而略有不同。虽然这些可以确定哪个更快,但它是用 10,000 个项目的列表进行测试的,所以如果您没有任何接近的项目,那么任何选择都可以。

import timeit
import random

# Code from above is here

def test(func_name):
    global test_lst
    test_lst = lst[:]
    return timeit.timeit("{}(test_lst)".format(func_name),
                         setup="from __main__ import {}, test_lst".format(func_name), number = 1)

if __name__ == '__main__':
    NUM_TRIALS = 1000
    lst = list(range(10000))
    random.shuffle(lst) # Don't have to but makes it a bit interesting
    test_list = lst[:]

    for func in ('example2', 'example3', 'example4', 'example5',
                 'example6', 'example7', 'example8', 'example9'):
        trials = []
        for _ in range(NUM_TRIALS):
            trials.append(test(func))
        print(func, sum(trials) / len(trials) * 10000)

#Output
example2 8.487979147454494
example3 20.407155912623292
example4 5.4595031069025035
example5 7.945100572479213
example6 14.43537688078149
example7 9.088818018676008
example8 14.898256300967116
example9 13.865010859443247

关于Python 3 : Removing list item with for loop, 这是正确的方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40539644/

相关文章:

c# - C# 中的方法上下文中无法识别列表实例

python - 如何确定一段文本的语言?

python - 使用python从CSV插入到oracle表中

python - 如何在背景中绘制文字和图像?

Python:如何添加两个列表,其中与该键的值相同的键没有重复值?

python - 如何迭代两个字典并将它们保存在python列表中

regex - 查找正则表达式匹配并删除匹配的外部部分

python - 如何使用 diff() 函数来识别 Pandas 中的薪资变化以进行人力资源分析?

python - 在 Python 请求中使用 POST 表单数据上传图像

python-3.x - Python-OpenCV cv2 OpenCV错误: Assertion failed