我的问题很简单:我有一长串的元素我想迭代并根据条件检查每个元素。根据条件的结果,我想删除列表的当前元素,并继续像往常一样迭代它。
我已经在这个问题上阅读了其他几个主题。提出两种解决方案。要么从列表中创建一个字典(这意味着要复制已经填满我所有RAM的所有数据)。要么反向走列表(这打破了我想要实现的算法的概念)。
有没有比这更好或更优雅的方法呢?
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
答案 0 :(得分:13)
答案 1 :(得分:6)
创建列表的过滤副本更有效,可以使用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
答案 2 :(得分:6)
如果您必须从原始列表中删除项目,并且没有足够的内存来制作副本,那么这是一个替代答案 - 自己将项目向下移动:
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足够智能,可以调整列表大小,而无需为列表的新副本分配内存。
答案 3 :(得分:4)
内置过滤器功能只是为了这样做:
list_of_g = filter(lambda x: not subtle_condition(x), list_of_g)
答案 4 :(得分:1)
这个怎么样?
[x for x in list_of_g if not subtle_condition(x)]
它返回新列表,但是来自subtle_condition
答案 5 :(得分:1)
为简单起见,请使用列表解析:
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]
答案 6 :(得分:1)
对于过滤功能来说,这听起来非常好用。
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
答案 7 :(得分:0)
如果执行反向迭代,您可以动态删除元素而不会影响您将访问的下一个索引:
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
enumerate(reversed(numbers))
只是一种风格选择。如果您更清晰,可以使用范围:
l = len(numbers)
for i in range(l-1, -1, -1):
n = numbers[i]
if n % 3 == 0:
del numbers[i]
如果您需要按顺序遍历列表,则可以在反向迭代之前和之后使用.reverse()
将其反转。这也不会重复您的列表。