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

python中使用for循环的列表迭代的奇怪行为,python,list,python-3.x,for-loop,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 =

我遇到了一种情况,在类似的情况下,我的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))
导入时间
def贪婪运输(奶牛,限制=10):
权重=[]
用于牛的重量。值():
权重。附加(权重)
权重.排序(反向=真)
cows\u copy=cows.copy()
所有行程=[]
而(长度(重量)>0):
有效重量=极限
当前行程=[]
对于以重量表示的重量:

如果权重则问题在于权重中权重的循环

循环在列表中的项目上迭代,但是Python循环使用项目的位置来实现这一点。当您删除带有
权重的项目时。删除(权重)
列表会缩小,而位置通常会增加1。基本上,因为您在遍历列表时从权重中删除项目,所以它会遍历其他项目,因此在收缩时会显示不同的列表长度(您可以通过将所有权重设置为1来验证这一点;您将获得与2相同的结果)

正在发生的事情的一个例子:

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循环在副本上迭代,同时从原始副本中删除:

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
# --> []
哇!你看那件作品真漂亮。对于你的母牛,看起来像这样:

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']]
def贪心牛运输(牛,限制=10):
权重=[]
用于牛的重量。值():
权重。附加(权重)
权重.排序(反向=真)
cows\u copy=cows.copy()
所有行程=[]
而(长度(重量)>0):
有效重量=极限
当前行程=[]
对于权重中的权重。复制():

如果你的代码应该把一个dict分解成几个部分,每个部分都有一个总的值,那么我们得到的总是细微的细节,不是吗?非常次要的旁注:你对
权重的整个初始化可以简化为
weights=sorted(cows.values(),reverse=True)
。即使不需要排序,使用重复的
append
s未修改值的显式循环也会简化为单个
.extend
调用(或者如果列表最初是空的,只需直接使用
list(someiterable)
构建它),
list
缺少
copy
方法(后来添加该方法是为了与
set
dict
等内容保持一致)。如果您的代码可能在早期版本的Python上运行,
for weight in weights[:]:
在任何版本上都可以正常工作;“空”切片是Python的习惯用法,用于浅层复制任意序列。您也可以按相反顺序循环位置索引,而不是创建列表的副本。例如,从后面。ShadowRanger。我不知道正确的协议,我应该在我的答案中添加你的内容,还是让你在评论中找到它?你可以编辑并在答案底部留下一个便条,说明这个想法来自@ShadowRanger。大多数人并不真正阅读评论。