在不使用Python中的额外内存的情况下,在迭代时从列表中删除项

在不使用Python中的额外内存的情况下,在迭代时从列表中删除项,python,list,iteration,Python,List,Iteration,我的问题很简单:我有一个很长的元素列表,我希望遍历这些元素,并根据条件检查每个元素。根据条件的结果,我希望删除列表中的当前元素,并像往常一样继续对其进行迭代 关于这件事,我还读了其他一些文章。将提出两种解决办法。或者从列表中创建一个字典(这意味着在我的例子中创建一个已经填充了所有RAM的所有数据的副本)。要么反向遍历列表(这打破了我想要实现的alogrithm的概念) 还有比这更好或更优雅的方法吗 def walk_list(list_of_g): g_index = 0 whi

我的问题很简单:我有一个很长的元素列表,我希望遍历这些元素,并根据条件检查每个元素。根据条件的结果,我希望删除列表中的当前元素,并像往常一样继续对其进行迭代

关于这件事,我还读了其他一些文章。将提出两种解决办法。或者从列表中创建一个字典(这意味着在我的例子中创建一个已经填充了所有RAM的所有数据的副本)。要么反向遍历列表(这打破了我想要实现的alogrithm的概念)

还有比这更好或更优雅的方法吗

def walk_list(list_of_g):
    g_index = 0
    while g_index < len(list_of_g):
        g_current = list_of_g[g_index]
        if subtle_condition(g_current):
            list_of_g.pop(g_index)
        else:
            g_index = g_index + 1
def walk_列表(列表):
g_指数=0
当g_索引
这个怎么样

[x for x in list_of_g if not subtle_condition(x)]

它返回新的列表,但不符合微妙的条件

为简单起见,请使用列表理解:

def walk_list(list_of_g):
    return [g for g in list_of_g if not subtle_condition(g)]
当然,这不会改变原始列表,因此调用代码必须不同

如果你真的想改变列表(很少是最好的选择),向后走比较简单:

def walk_list(list_of_g):
    for i in xrange(len(list_of_g), -1, -1):
        if subtle_condition(list_of_g[i]):
            del list_of_g[i]
而且

li = filter(condition,li) 

内置过滤器功能就是为了实现这一点:

list_of_g = filter(lambda x: not subtle_condition(x), list_of_g)

从列表中删除项目的代价很高,因为python必须将g_索引上方的所有项目向下复制一个位置。如果要删除的项的数量与列表的长度N成正比,那么您的算法将是O(N**2)。如果列表足够长,足以填满RAM,那么您将等待很长时间才能完成

更有效的方法是创建列表的筛选副本,如Marcelo所示使用列表理解,或使用filter或itertools.ifilter函数:

g_list = filter(not_subtle_condition, g_list)
如果您不需要使用新列表,只想在其上迭代一次,那么最好使用ifilter,因为这样不会创建第二个列表:

for g_current in itertools.ifilter(not_subtle_condtion, g_list):
    # do stuff with g_current

听起来是一个非常好的过滤器功能用例

def should_be_removed(element):
  return element > 5

a = range(10)
a = filter(should_be_removed, a)
但是,这不会在迭代时删除列表(我也不建议这样做)。如果出于内存空间(或其他性能原因)您确实需要它,可以执行以下操作:

i = 0
while i < len(a):
    if should_be_removed(a[i]):
        a.remove(a[i])
    else:
        i+=1
    print a
i=0
而我
如果您必须从原始列表中删除项目,并且您没有足够的内存进行复制,那么这里有一个备选答案-请您自己将项目从列表中向下移动:

def walk_list(list_of_g):
    to_idx = 0
    for g_current in list_of_g:
        if not subtle_condition(g_current):
            list_of_g[to_idx] = g_current
            to_idx += 1
    del list_of_g[to_idx:]

这将移动每个项目(实际上是指向每个项目的指针)一次,O(N)也将如此。函数末尾的del语句将删除列表末尾的任何不需要的项,我认为Python足够智能,可以调整列表大小,而无需为列表的新副本分配内存。

如果执行反向迭代,可以动态删除元素,而不会影响您将访问的下一个索引:

numbers = range(20)

# remove all numbers that are multiples of 3
l = len(numbers)
for i, n in enumerate(reversed(numbers)):
    if n % 3 == 0:
        del numbers[l - i - 1]

print numbers
枚举(反转(数字))
只是一种风格选择。如果您更清楚,可以使用范围:

l = len(numbers)
for i in range(l-1, -1, -1):
    n = numbers[i]
    if n % 3 == 0:
        del numbers[i]

如果需要按顺序遍历列表,可以在反转迭代前后使用
.reverse()
将其反转到位。这也不会复制您的列表。

复制所有这些内容:。明确地说,是的,在发布我的问题之前,我仔细阅读了你链接到的其他帖子。在另一个线程中提出的答案都没有解决我的问题。这是因为我的问题不同于复制列表和向后遍历列表。按元素删除可能会更慢或更快,具体取决于列表的内容。我喜欢它。尽管它不是很“Pythonic”,但它回答了这个问题,并且仍然非常流畅。正如Alex Martelli在:li[:]=[x代表x,如果条件(x)]中所建议的那样,这是一个更好的方法。
l = len(numbers)
for i in range(l-1, -1, -1):
    n = numbers[i]
    if n % 3 == 0:
        del numbers[i]