Python for循环和操作

时间:2015-10-18 20:47:37

标签: python

嘿伙计们,我在stackoverflow上找到了另一篇文章中的代码,我发现了一些关于" for循环"的内容。如果您使用" pop"更改列表或"删除"它弄乱了内部循环的索引。如果您从列表中弹出/删除项目,它将跳过整个项目。我绕过它的方法是实际制作一个列表的副本,用于" for循环"我操纵了另一个清单。我是python的新手。

我加入了他的名单。我的程序删除了任何体重超过180或任何名为乔的人。起初我在发现这个问题时刚刚使用了d_list。然后我只是" temp_list = d_list"我认为它是一个单独的副本,但我想不是。然后我使用列表的copy属性使其工作。这样我就不会操纵列表" for循环"正在使用。

我的问题是,这是正常的,我是否正确解决它?对我来说,如果数据很大,你就不想制作数据副本。我提出的另一个选择是使用while循环而不是外部for循环。

d_list = [ {'id':1, 'Name': 'Hannah', 'weight':150}, {'id':2, 'Name':'Andrew', 'weight':200}, {'id':3, 'Name':'Joe', 'weight':180},
           {'id':4, 'Name':'Joe', 'weight':180}, {'id':5, 'Name':'Steve', 'weight':200}, {'id':6, 'Name':'Joe', 'weight':180},
           {'id':7, 'Name':'George', 'weight':180}]

temp_list = d_list
#temp_list = d_list.copy()
print(d_list)
i = 0
for item in temp_list: # may make a while loop
    print(item, "i = ", i, end="[")
    for k, v in item.items():
        print(end="*")
        if (k == "weight") and (v > 180):
            d_list.pop(i)
            print('^popped^', i, end="")  # <-- pop but you need an index
            i -= 1
        elif (k == "Name") and (v == "Joe"):
            d_list.remove(item)          # <-- remove just uses item to find and remove
            print("^removed^", i, end="")
            i -= 1
    i += 1
    print("]")
print(d_list)
print("i = ", i)

2 个答案:

答案 0 :(得分:1)

由于您发现的问题,最好通过制作合格元素的新列表来完成此类操作。此外,扫描所有键和值是愚蠢的;通过查找键来使用字典:

newlist = []
for item in d_list:
    if item["weight"] <= 180 and item["Name"] != "Joe":
        newlist.append(item)

如果您担心&#34;浪费&#34;那么您可以释放旧列表。空间:

del d_list

答案 1 :(得分:0)

temp_list = d_list会创建一个引用,因此任何一个列表中的任何更改都会反映在两者中,这样肯定不起作用。 temp_list = d_list.copy()创建一个浅层副本,它可以像temp_list = d_list[:]那样工作,但是更好的方法是避免任何复制,只需要使用reversed并从列表中删除元素:

for item in reversed(d_list): 
    if item.get("weight", 0) > 180 or item.get("Name") == "Joe":
        d_list.remove(item)
        i -= 1

如果你想要弹出,你可以在最后使用反向范围开始:

for i in range(len(d_list) -1 , -1, - 1): 
    item = d_list[i]
    if item.get("weight", 0) > 180 or item.get("Name") == "Joe":   
        i -= 1

第三个选项是list comprehension使用d_list[:]来改变原始对象/列表:

d_list[:]  = [d for d in d_list if  d.get("weight", 0) <= 180  and  d.get("Name")  != "Joe"]

或者将其与generator expression

结合使用
d_list[:] = (d for d in d_list if d.get("weight", 0) <= 180 and d.get("Name") != "Joe")

所有方法都会为您提供相同的输出。使用dict.get而不是迭代所有项也是一种更有效的解决方案,我们每次迭代执行两次查找,而不是查看每个dict中的所有键和值。

使用python3的一些时间:

In [14]: %%timeit
d_list = [{'id': 1, 'Name': 'Hannah', 'weight': 150}, {'id': 2, 'Name': 'Andrew', 'weight': 200},
          {'id': 3, 'Name': 'Joe', 'weight': 180},
          {'id': 4, 'Name': 'Joe', 'weight': 180}, {'id': 5, 'Name': 'Steve', 'weight': 200},
          {'id': 6, 'Name': 'Joe', 'weight': 180},
          {'id': 7, 'Name': 'George', 'weight': 180}]
for item in reversed(d_list):    
    if item.get("weight", 0) > 180 or item.get("Name") == "Joe":
        d_list.remove(item)
   ....: 
100000 loops, best of 3: 4.35 µs per loop

In [15]: %%timeit
d_list = [{'id': 1, 'Name': 'Hannah', 'weight': 150}, {'id': 2, 'Name': 'Andrew', 'weight': 200},
          {'id': 3, 'Name': 'Joe', 'weight': 180},
          {'id': 4, 'Name': 'Joe', 'weight': 180}, {'id': 5, 'Name': 'Steve', 'weight': 200},
          {'id': 6, 'Name': 'Joe', 'weight': 180},
          {'id': 7, 'Name': 'George', 'weight': 180}]
for i in range(len(d_list) - 1, -1, - 1):  # may make a while loop
    item = d_list[i]
    if item.get("weight", 0) > 180 or item.get("Name") == "Joe":
        d_list.pop(i)
   ....: 
   ....:     
100000 loops, best of 3: 4.48 µs per loop

In [16]: %%timeit
   ....: d_list = [{'id': 1, 'Name': 'Hannah', 'weight': 150}, {'id': 2, 'Name': 'Andrew', 'weight': 200},
   ....:           {'id': 3, 'Name': 'Joe', 'weight': 180},
   ....:           {'id': 4, 'Name': 'Joe', 'weight': 180}, {'id': 5, 'Name': 'Steve', 'weight': 200},
   ....:           {'id': 6, 'Name': 'Joe', 'weight': 180},
   ....:           {'id': 7, 'Name': 'George', 'weight': 180}]
   ....: d_list[:] = (d for d in d_list if d.get("weight", 0) <= 180 and d.get("Name") != "Joe")
   ....: 
100000 loops, best of 3: 3.23 µs per loop

In [17]: %%timeit
d_list = [{'id': 1, 'Name': 'Hannah', 'weight': 150}, {'id': 2, 'Name': 'Andrew', 'weight': 200},
          {'id': 3, 'Name': 'Joe', 'weight': 180},
          {'id': 4, 'Name': 'Joe', 'weight': 180}, {'id': 5, 'Name': 'Steve', 'weight': 200},
          {'id': 6, 'Name': 'Joe', 'weight': 180},
          {'id': 7, 'Name': 'George', 'weight': 180}]
d_list[:] = [d for d in d_list if d.get("weight", 0) <= 180 and d.get("Name") != "Joe"]
   ....: 
100000 loops, best of 3: 2.98 µs per loop

因此列表comp是最快的,然后是gen exp。如果您知道密钥始终存在,那么使用d["weight"]等进行访问也会更快