Python迭代的惯用方法,用于遍历可变列表。

3

在Python中,是否有更好(更明显/惯用)的方法来编写以下等效内容:

index = 0
while index < len(some_list):
    do_some_stuff(some_list[index]) # may have many side effects
    if delete_element(some_list[index]):
        del some_list[index]
    else:
        index += 1

还是要用字典吗?因为delete_element的结果可能取决于do_some_stuff,所以字典/列表推导式不适用。
4个回答

3
你可以将操作分成两个独立的循环,并在第二部分使用列表推导式。
for value in some_list:
    do_some_stuff(value)

some_list = [value for value in some_list if not delete_element(value)]

另一个解决方案是迭代列表的副本,并使用enumerate来跟踪索引,而无需手动维护计数器。
for index, value in enumerate(some_list[::-1]):
    do_some_stuff(value)
    if delete_element(value):
        del some_list[-index - 1]

您需要反向迭代,这样就不必为删除的元素调整index


2
enumerate 从零开始计数,即使在反向迭代器上调用它时也是如此。您需要使用 del some_list[-index-1],以便删除的索引随着项目一起递减。 - Blckknght

1
如果顺序不重要,您可以倒序枚举,以便删除不会破坏您尚未处理的列表部分。
for i, item in enumerate(reversed(somelist), -len(somelist)+1):
    do_some_stuff(item)
    if delete_element(item):
        del somelist[-i]

如果顺序很重要,反转列表,然后再次反转。这会让他们困惑!
根据情况,您可以使用 None 这样的标记替换项目。稍后将其去除或在使用此列表的其他位置检查 None。
for i, item in enumerate(somelist)):
    do_some_stuff(item)
    if delete_element(item):
        somelist[i] = None

somelist = [item for item in somelist if item]

你的 enumerate 调用不会生成与反转值匹配的索引 (somelist[-len(somelist)+1]somelist[0])。你可能想要使用 enumerate(reversed(somelist), 1),然后在稍后使用 del somelist[-index] - Blckknght
@Blckknght - 没错,我想用 abs(i)。enumerate 不会倒数计数,所以诀窍是从负数开始,让它逐渐到达零。但是,正如您所说,使用负索引会删除错误的值。 - 在代码中已修复。 - tdelaney
啊,这样做确实更好。不过,我会使用-i而不是abs(i),因为后者会检查值的符号,而你并不需要(你总是想要否定现有的值)。 - Blckknght
@Blckknght - 这个也改了。每次循环节省了0.00000003秒(微笑)。 - tdelaney
考虑到我未明确说明要就地修改列表的要求,这个答案最适合。它还教会了我通过传递第二个参数给enumerate的巧妙技巧。 - Anaphory

0

假设do_some_stuff返回item,你甚至可以这样做:

res = [item for item in some_list if not delete_element(do_some_stuff(item))]

0

没有废话的方法是使用生成器:

def do_stuff_and_filter_items(items):
    for item in items:
        do_some_stuff(item)
        if not delete_element(item):
            yield item

那么要获得一个可迭代对象:

items = do_stuff_and_filter_items(items)

或者获取一个列表:

items = list(do_stuff_and_filter_items(items))

或者覆盖旧列表:

items[:] = do_stuff_and_filter_items(items)

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