我的数据结构如下:
def cross(A, B):
return [a+b for a in A for b in B]
digits = '123456789'
rows = 'ABCDEFGHI'
cols = digits
squares = cross(rows, cols)
unitlist = ([cross(rows, c) for c in cols] +
[cross(r, cols) for r in rows] +
[cross(rs, cs) for rs in ('ABC', 'DEF', 'GHI') for cs in ('123', '456', '789')])
units = dict((s, [u for u in unitlist if s in u]) for s in squares)
peers = dict((s, set(sum(units[s],[]))-set([s])) for s in squares)
这会导致单位输出
{'A1': [['A1','A2','A3','A4','A5','A6','A7','A8','A9'],
['A1','B1','C1','D1','E1','F1','G1','H1','I1'],
['A1','A2','A3','B1','B2','B3','C1','C2','C3']],
'A2': [['A1','A2','A3','A4','A5','A6','A7','A8','A9'],
['A2','B2','C2','D2','E2','F2','G2','H2','I2'],
['A1','A2','A3','B1','B2','B3','C1','C2','C3']],
'A3': [[etc.]]}
我希望能够创建单元的副本,但是不要让KEY成为其自己的列表中的字符串。所以我希望从前3个列表中删除'A1'。 'A2'从接下来的3个名单中删除等等。
我可以导入副本并执行units2 = copy.deepcopy(units)
然后units2['A1'][0].remove('A1')
一次执行一个列表。所以这让我尝试制作一个循环来同时完成所有操作。
for s in squares: #assign s to 'A1' then 'A2', etc.
for x in range(3): #
units2[s][x].remove(s)
我认为通过运行
可以完美地完成它units2['A1'][0].remove('A1')
units2['A1'][1].remove('A1')
units2['A1'][2].remove('A1')
units2['A2'][0].remove('A2')
# etc.
不幸的是,在运行此循环后,我最终得到:
units2 = {'B8': [[], [], []],
'H1': [[], [], []],
'C7': [[], [], []],
'B3': [[], [], []],
# etc.
}
所以不知何故,这个循环正在删除列表中的所有数据,而不仅仅是当前[x]列表中的当前[s]。
我尝试过以不同的方式构建列表,甚至制作了81个版本的
for x in range(3):
units2['A1'][x].remove('A1')
for x in range(3):
units2['A2'][x].remove('A2')
for x in range(3):
units2['A3'][x].remove('A3')
但我仍然以空列表作为我的所有词典值。
*我正在尝试做的是构建一个数独求解器然后用于在PyGame中为游戏生成sudokus。我计划使用units2
中的列表来检查并查看任何给定列表中是否只有1个单元格仍然符合特定号码的条件。如果是这种情况,我知道该单元格必须将该数字作为其值,因为它是列,行或9x9块中唯一可以根据规则合法保留它的块。
答案 0 :(得分:1)
使用嵌套列表推导更改单位:
units = dict((s, [[e for e in u if s != e]
for u in unitlist if s in u]) for s in squares)
答案 1 :(得分:1)
如果你看一下这里发生了什么,然后退一步,答案就变得很明显了。
毫无疑问,你知道是什么导致这种情况:
In [1]: a = [1,2,3]
In [2]: b = a
In [3]: a.remove(2)
In [4]: print(a)
[1, 3]
In [5]: print(b)
[1, 3]
这就是你copy.deepcopy
的原因。但是当你看看发生了什么时,如果你使用Occam's Razor,显而易见的答案就是你有多个对同一个列表的引用,当你从另一个列表中删除最终清空 all 您的结构中的列表。这是一个简单的方法来检查:
import collections
import pprint
counter = collections.Counter()
for s in squares:
for x in range(3):
counter[id(units2[s][x])] += 1
pprint.pprint(counter)
哪些输出(不出所料):
Counter({140502086261512: 9,
140502086288328: 9,
140502086261256: 9,
140502086287688: 9,
140502086288008: 9,
# and so on...
})
显然,您的id
会有所不同,但计数都是9
。
如果您将units2
替换为units
,您将获得相同的计数。所以这里真正的问题是为什么copy.deepcopy
没有像你想象的那样表现?为什么列表列表中有相同列表的多个副本?
让我们尝试一些实验:
list_of_lists = [[1,1,1],
[2,2,2],
[3,3,3],
]
deepcopy_of_lists = copy.deepcopy(list_of_lists)
print(id(list_of_lists))
print(id(deepcopy_of_lists))
我希望这里有两个不同的id,实际上它们是。但他们的内容呢?
print(id(list_of_lists[0]))
print(id(deepcopy_of_lists[0]))
是的。那些是不同的。如果我们把它们放在字典中怎么办?
dict_of_list_of_lists = {'list_of_lists': list_of_lists}
deepcopy_of_dict = copy.deepcopy(dict_of_list_of_lists)
print(id(dict_of_list_of_lists['list_of_lists'][0]))
print(id(deepcopy_of_dict['list_of_lists'][0]))
我们仍然获得不同的id
。一切似乎都像预期的那样表现,所以显然我们错过了一些东西。哦,是的 - 我们在复制的列表和原始列表之间进行比较。
如果您将
units2
替换为units
,则会获得相同的计数。
有一个提示。另外,如果您阅读deepcopy documentation:
深拷贝操作经常存在两个问题:浅拷贝操作不存在:
- 递归对象(直接或间接包含对自身的引用的复合对象)可能会导致递归循环。
- 因为深拷贝会复制它可能复制的所有内容,例如,即使在副本之间也应该共享的管理数据结构。
deepcopy()函数通过以下方式避免了这些问题:
- 保留当前复制过程中已复制的对象的“备忘录”字典;和
- 让用户定义的类覆盖复制操作或复制的组件集。
deepcopy
会关注已经看过的对象。
mylist = [1,2,3]
list_of_mylist = [mylist, mylist, mylist]
deepcopy_of_mylist = copy.deepcopy(list_of_mylist)
print(id(deepcopy_of_mylist[0]))
print(id(deepcopy_of_mylist[1]))
瞧!我们有罪魁祸首!
在原始字典units
中,您有多个副本到不同键中的相同列表。这是因为这一行:
units = dict((s, [u for u in unitlist if s in u]) for s in squares)
本节特别说明:
[u for u in unitlist if s in u]
您在整个字典中重复对unitlist
列表的引用。幸运的是,这是一个微不足道的修复:
[u[:] for u in unitlist if s in u]
每次都会制作该列表的副本,其余代码也能正常工作。
import pprint
import copy
import pprint
def cross(A, B):
return [a+b for a in A for b in B]
digits = '123456789'
rows = 'ABCDEFGHI'
cols = digits
squares = cross(rows, cols)
unitlist = ([cross(rows, c) for c in cols] +
[cross(r, cols) for r in rows] +
[cross(rs, cs) for rs in ('ABC', 'DEF', 'GHI') for cs in ('123', '456', '789')])
units = dict((s, [u[:] for u in unitlist if s in u]) for s in squares)
peers = dict((s, set(sum(units[s],[]))-set([s])) for s in squares)
units2 = copy.deepcopy(units)
for s in squares: #assign s to 'A1' then 'A2', etc.
for x in range(3): #
units2[s][x].remove(s)
pprint.pprint(units2)
输出:
{'A1': [['B1', 'C1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1'],
['A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9'],
['A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3']],
'A2': [['B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2'],
['A1', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9'],
['A1', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3']],
'A3': [['B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3'],
['A1', 'A2', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9'],
['A1', 'A2', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3']],
# and so on and so forth
}