在python中使用for循环的列表迭代的奇怪行为

时间:2017-03-30 12:23:03

标签: python list python-3.x for-loop

我遇到过类似情况下我的python代码表现不同的情况。这是代码:

import time
def greedy_cow_transport(cows,limit=10):
    weights = []
    for weight in cows.values():
        weights.append(weight)
    weights.sort(reverse=True)
    cows_copy = cows.copy()
    all_trips = []
    while (len(weights) > 0):
        avail_weight = limit
        curr_trip = []
        for weight in weights:
            if weight <= avail_weight:
                for n, w in cows_copy.items():
                    if weight == w:
                        curr_trip.append(n)
                        weights.remove(weight)
                        cows_copy.pop(n, None)
                        avail_weight -= w
                        break
        all_trips.append(curr_trip)
    return all_trips
cows = {'Lola': 2, 'Oreo': 2, 'Millie': 2, 'Betsy': 2, 'Moo Moo': 2, 'Milkshake': 2, 'Herman': 2, 'Florence': 2, 'Maggie': 2, 'Henrietta': 2}
limit=100
print(cows)
print(greedy_cow_transport(cows))

而不是greedy_cow_transport返回 2个5名成员的名单,它返回3个不同的5 3 2名成员名单。请解释为什么会发生这种情况?我知道,我可能会遗漏一些微妙的细节,但我需要帮助。无法弄清楚错误。 感谢。

1 个答案:

答案 0 :(得分:1)

问题在于循环subscription

循环遍历列表中的项目,但Python循环使用项目的位置来执行此操作。当您使用for weight in weights:删除项目时,列表会缩小,而位置会像往常一样增加1。基本上,因为你在迭代列表时从权重中删除项目,它会覆盖每个其他项目 - 因此缩小时不同的列表长度(您可以通过将所有权重设置为1来验证这一点;您将获得与2)相同的结果

正在进行的一个例子:

weights.remove(weight)

^^注意它是如何只迭代其他所有项目的。确切地说,list = [1, 2, 3, 4, 5] for item in list: print(item) list.remove(item) print(list) # --> 1 # --> [2, 3, 4, 5] # --> 3 # --> [2, 4, 5] # --> 5 # --> [2, 4]

正在发生什么

一个简单的解决方法是让你的for循环遍历副本,同时从原始文件中删除:

weights

WOW!看看这部作品如此美妙。对于你的奶牛看起来像这样:

list = [1, 2, 3, 4, 5]
for item in list.copy():
    print(item)
    list.remove(item)
    print(list)

# --> 1
# --> [2, 3, 4, 5]
# --> 2
# --> [3, 4, 5]
# --> 3
# --> [4, 5]
# --> 4
# --> [5]
# --> 5
# --> []

瞧!希望你喜欢。

@ShadowRanger补充说,在旧版本的Python中,list没有复制方法,因此def greedy_cow_transport(cows,limit=10): weights = [] for weight in cows.values(): weights.append(weight) weights.sort(reverse=True) cows_copy = cows.copy() all_trips = [] while (len(weights) > 0): avail_weight = limit curr_trip = [] for weight in weights.copy(): if weight <= avail_weight: for n, w in cows_copy.items(): # <--!!! THE CHANGE IS HERE if weight == w: curr_trip.append(n) weights.remove(weight) cows_copy.pop(n, None) avail_weight -= w break all_trips.append(curr_trip) return all_trips cows = {'Lola': 2, 'Oreo': 2, 'Millie': 2, 'Betsy': 2, 'Moo Moo': 2, 'Milkshake': 2, 'Herman': 2, 'Florence': 2, 'Maggie': 2, 'Henrietta': 2} print(greedy_cow_transport(cows)) # --> [['Oreo', 'Milkshake', 'Herman', 'Florence', 'Lola'], ['Maggie', 'Millie', 'Henrietta', 'Betsy', 'Moo Moo']] 的替代方法是使用像list.copy()这样的空切片。