我正在通过Project Euler编程,我遇到了一个奇怪的问题.我想找到从两个自然数生成(自然)数字的所有可能方法.我创建了一个简单的循环,我注意到了奇怪的结果.例如,1从3和1生成.一些调查结果如下:
#Importing stuff I often use in my solutions/tests
from math import sqrt, log, floor, pow, fabs, factorial
from sets import Set
from random import randint
from itertools import permutations
import sys
dub = dict()
c = 0 #Counting the number of elements in dub[18], use to track changes
for i in range (1,10):
if 18 in dub: #setting c = len(dub[18])
c = len(dub[18])
for j in range (i+1,10):
pair = [[i,j]]
v = i+j
if v in dub:
dub[v].append(pair[0])
else:
dub[v] = pair
v = i*j
if v in dub:
dub[v].append(pair[0])
else:
if i == 3 and j == 8: print 'here', v # The value that is added to dub[18] instead of dub[24]
dub[v] = pair
if 18 in dub and not c == len(dub[18]): #This is how I found that something is wrong.
c = len(dub[18])
print dub[18]
print v,i,j
raw_input()
Run Code Online (Sandbox Code Playgroud)
结果如下:
[[2, 9]]
18 2 9
[[2, 9], [3, 6]]
18 3 6
here 24
[[2, 9], [3, 6], [3, 8]]
24 3 8
Run Code Online (Sandbox Code Playgroud)
我应该使用的密钥是24,但是列表放在密钥18下面.为什么会这样?
您正在为多个键重复使用相同的列表.这条线
pair = [[i,j]]
Run Code Online (Sandbox Code Playgroud)
创建一个包含单个对的列表.此列表用于两个else分支
else:
dub[v] = pair
Run Code Online (Sandbox Code Playgroud)
导致使用相同列表对象的两个不同的键.由于它是同一个对象,因此附加到列表中的任何一个键都可以在另一个中看到.
编辑:这是一个演示此行为的最小示例:
>>> d = {}
>>> a = []
>>> d[0] = a
>>> d[1] = a
>>> d[0].append(2)
>>> d[0]
[2]
>>> d[1]
[2]
Run Code Online (Sandbox Code Playgroud)
显而易见的解决方法是仅将名称对分配给名称pair,并在需要时创建包含该对的新列表:
dub = {}
for i in range (1, 10):
for j in range (i + 1, 10):
pair = [i, j]
v = i + j
if v in dub:
dub[v].append(pair)
else:
dub[v] = [pair]
v = i * j
if v in dub:
dub[v].append(pair)
else:
dub[v] = [pair]
Run Code Online (Sandbox Code Playgroud)
要进一步简化此代码,您可以将ifs 替换为dict.setdefault():
dub = {}
for i in range (1, 10):
for j in range (i + 1, 10):
pair = [i, j]
dub.setdefault(i + j, []).append(pair)
dub.setdefault(i * j, []).append(pair)
Run Code Online (Sandbox Code Playgroud)