Python:del in for循环

时间:2015-04-06 18:58:09

标签: python

问题:

test1 = [1, 2, 3]
for i in range(len(test1)): #Want to do the below for every element in test1 
    print(test1[i])
    if test1[i] % 2 == 0: #if the element meets certain conditions, it gets deleted
        del test1[i] 
        #The thing in test1 gets deleted, but the range gets not updated,
        #and i iterates nonetheless, so 1 element gets ignored,
        #and in the end, I get "list index out of range"

(在实际的代码中,if语句要多得多,并且数组中的东西不是整数而是类的对象?!所以列表理解更多 - meh ......)

我提出了这种方法:

test1 = [1, 2, 3]
i = 0
x = len(test1)
while i < x:
    print(test1[i])
    if test1[i] % 2 == 0:
        del test1[i]
        x -= 1
        i -= 1
    i += 1

但正如你所看到的,这是5行(对于每个del,我必须添加2行......),丑陋和烦人。有没有更好的办法做这样的事情?比如,直接进入for循环的重做命令会更新范围,让你选择i或其他东西吗?

4 个答案:

答案 0 :(得分:6)

使用列表理解

有些事情:

list = [x for x in list if x % 2 == 1] # Keep anything that is not even
for thing in list:
    print(thing)

这将创建一个包含与条件匹配的任何内容的新列表。 然后打印新列表

>>> test1 = [1,2,3]
>>> list = [x for x in test1 if x % 2 is 1]
>>> print(list)
[1, 3]

答案 1 :(得分:3)

您是否尝试过使用范围内的reversed

test1 = [1, 2, 3]
for i in reversed(range(len(test1))):
    print(test1[i])
    if test1[i] % 2 == 0:
        del test1[i]
>>> 3
>>> 2
>>> 1

print(test1)
>>> [1, 3]

这样,当你删除一个元素时,数组会减少,但由于你以相反的顺序浏览列表,所以只有已处理元素的索引才会受到影响。

修改

阅读完所有评论后,我决定运行一些小基准测试。我创建了一个包含1,000个元素的列表和10,000,000个元素的列表,并试用了3种方法:

  • #1从列表中删除
  • #2使用列表推导创建新列表
  • #3使用classic为
  • 创建新列表

对于1,000个元素的列表,时间并不重要,但对于10,000,000个元素列表,从列表中删除几乎是不可能的(创建一个新列表需要几个小时vs半秒)。

使用1,000个元素进行测试

>>> Test 0, 11th element: 7e-06 seconds
>>> Test 0, second last element: 2e-06 seconds
>>> Test 1: 0.00017 seconds
>>> Test 2: 0.000103 seconds
>>> Test 3: 0.000234 seconds

使用10,000,000元素进行测试

>>> Test 0, 11th element: 0.011888 seconds
>>> Test 0, second last element: 4e-06 seconds
>>> Test 1: Too long!!
>>> Test 2: 0.941158 seconds
>>> Test 3: 0.681262 seconds

关于这一点,我强烈建议使用列表推导或定期for循环创建一个新列表。

这是我的代码:

from datetime import datetime
from random import randint


# Create my test lists of 10 000 000 elements
test_0 = []
#nb_el = 10000000
nb_el = 1000
while (len(test_0) < nb_el):
    test_0.append(randint(0, 100))
test_1 = test_0[:] # clone list1
test_2 = test_0[:] # clone list1
test_3 = test_0[:] # clone list1


# Test #0
# Remove the 11th element and second last element
d1 = datetime.now()
del test_0[10]
d2 = datetime.now()
print('Test 0, 11th element: ' +
    str((d2-d1).microseconds / 1000000.0) + ' seconds')

d1 = datetime.now()
del test_0[nb_el-2]
d2 = datetime.now()
print('Test 0, second last element: '
    + str((d2-d1).microseconds / 1000000.0) + ' seconds')


# Test #1 | TOO SLOW TO BE RAN with 10 000 000 elements
# Delete every element where element is a multiple of 2
d1 = datetime.now()
for i in reversed(range(len(test_1))):
    if test_1[i] % 2 == 0:
        del test_1[i]
d2 = datetime.now()
print('Test 1: ' + str((d2-d1).microseconds / 1000000.0) + ' seconds')

# Test #2
# Create a new list with every element multiple of 2
# using list comprehension
d1 = datetime.now()
test_2_new = [x for x in test_2 if x % 2 == 0]
d2 = datetime.now()
print('Test 2: ' + str((d2-d1).microseconds / 1000000.0) + ' seconds')

# Test #3
# Create a new list with every element multiple of 2
# using for loop
d1 = datetime.now()
test_3_new = []
for i in range(len(test_3)):
    if test_3[i] % 2 == 0:
        test_3_new.append(test_3[i])
d2 = datetime.now()
print('Test 3: ' + str((d2-d1).microseconds / 1000000.0) + ' seconds')

答案 2 :(得分:3)

假设您想要从列表中删除它们之前打印每个数字。

myList = [1,2,3]

for n in test1:
    print n

test1 = [n for n in myList if n % 2] # 0 = False by default in python. No need for == 0 / > 0.

如果您绝对想要使用您编写的代码,因为您可能更容易理解:

test1 = [1, 2, 3]
for i in range(len(test1)): #Want to do the below for every element in test1 
    print(test1[i])


    # Either check if the index is not greather than the length of the list.

    if test1[i] % 2 == 0 and i <= len(test1): #if the element meets certain conditions, it gets deleted

    # Or use try, except (Will be slow if your list is great in size as there will be many exceptions caught.

    if test1[i] % 2 == 0:
        try:
            del test1[i] 
        except:
            continue
        #The thing in test1 gets deleted, but the range gets not updated,
        #and i iterates nonetheless, so 1 element gets ignored,
        #and in the end, I get "list index out of range"

答案 3 :(得分:1)

在您迭代迭代时修改迭代可能会给您带来很多麻烦。请尝试以下方法:

test1 = [1,2,3]
test2 = []
for i in test1:
    print(i)
    if i%2:
        test2.append(i)

然后你有test2作为完成版本。

这可以通过理解更紧凑地编写:

test1 = [1,2,3]
test2 = [i for i in test1 if i%2]
print(*test2, sep='\n')