【问题标题】:Is this code for making a nested dictionary correct?这个用于制作嵌套字典的代码是否正确?
【发布时间】:2020-12-08 12:10:03
【问题描述】:

我在这篇文章的答案中给出的代码有一些问题: Can I use a nested for loop for an if-else statement with multiple conditions in python?

import pprint

board = {
    '1a': 'bking',
    '4e': 'bpawn',
    '2c': 'bpawn',
    '3f': 'bpawn',
    '5h': 'bbishop',
    '6d': 'wking',
    '7f': 'wrook',
    '2b': 'wqueen'
}

count = {}
for k, v in board.items():
    count[k[0]][k[1:]] = v
pprint.pprint(count)

我想得到以下字典:

count = {'b': {'king': 1, 'pawn': 3, 'bishop': 1},
         'w': {'king': 1, 'rook': 1, 'queen': 1}}

收到错误:

Traceback (most recent call last):
  File "/Users/Andrea_5K/Library/Mobile Documents/com~apple~CloudDocs/automateStuff2/ch5/flatToNest2.py", line 21, in <module>
    count[k[0]][k[1:]] = v
KeyError: '1'

【问题讨论】:

  • 将堆栈跟踪添加到您的问题中
  • @MadPhysicist 你是什么意思?我在这个问题中添加了一个指向 OP 的链接,并在 OP 的评论中添加了一个指向这个问题的链接。你还想让我做什么?
  • 您需要发布预期输出和异常消息
  • 另外,你想对位置信息做些什么吗?

标签: python dictionary for-loop


【解决方案1】:

OP 评论说输出应该是每件的计数。这可以使用setdefault

来完成
nested = {}
for k, v in board.items():
    nested.setdefault(v[0], {})  # default dictionary for missing key
    nested[v[0]][v[1:]] = nested[v[0]].get(v[1:], 0) + 1 # increment piece count

pprint.pprint(nested)
# Result
{'b': {'bishop': 1, 'king': 1, 'pawn': 3},
 'w': {'king': 1, 'queen': 1, 'rook': 1}}

【讨论】:

  • 像这样使用setdefault 的缺点是它总是会创建一个新字典,而这主要是浪费。
  • @MadPhysicist——如果字典不存在,它不只是制作一本字典吗?然后下一行使用字典,即nested[k[0]][k[1:]]
  • 不,如果键不存在,它只会添加字典。 {} 总是创建一个新字典
  • @MadPhysicist——是的,我同意 setdefault(...) 总是评估默认值。那么您是说对默认值的评估是一个问题,因为它创建了一个可能不会被使用的默认字典?我同意defaultdict is faster,但我认为在这种情况下速度差异没有意义。同意吗?
  • 这正是我要说的。在这种情况下,速度和微小的内存碎片可能不是问题,但需要注意。
【解决方案2】:

您的代码中的问题是,当您访问nested[k[0]] 时,您希望nested 已经拥有这个键,并且您希望相应的值是一个字典。

解决此问题的最简单方法是使用defaultdict(dict),它会在需要时即时创建:

from collections import defaultdict

board = {
    '1a': 'bking',
    '4e': 'bpawn',
    '2c': 'bpawn',
    '3f': 'bpawn',
    '5h': 'bbishop',
    '6d': 'wking',
    '7f': 'wrook',
    '2b': 'wqueen'
}

nested = defaultdict(dict)
for k, v in board.items():
    nested[k[0]][k[1:]] = v
print(nested)

# defaultdict(<class 'dict'>, {'1': {'a': 'bking'}, '4': {'e': 'bpawn'}, '2': {'c': 'bpawn', 'b': 'wqueen'}, '3': {'f': 'bpawn'}, '5': {'h': 'bbishop'}, '6': {'d': 'wking'}, '7': {'f': 'wrook'}})

【讨论】:

  • 谢谢。但我需要另一个解决方案:我的嵌套字典应该包含棋盘中每一块的计数。例如:count = {'b': {'king': 1, 'pawn': 3, 'bishop': 1}, 'w': {'king': 1, 'rook': 1, 'queen' : 1}}
【解决方案3】:

如果您只需要计数,请使用collections.Counter,然后使用collections.defaultdict 拆分结果:

counts = defaultdict(dict)
for piece, count in Counter(board.values()).items():
    counts[piece[0]][piece[1:]] = count

【讨论】:

  • 谢谢。我只需要字典计数 = {'b': {'king': 1, 'pawn': 3, 'bishop': 1}, 'w': {'king': 1, 'rook': 1, '女王':1}})。因为我想将它用于不同的验证测试,正如您在 OP 中提到的那样。您的意思是如何拆分结果?
  • @aurumpurum。我很确定这就是我要输出的内容,但我在移动设备上,所以现在无法测试
  • 变量 counts 保存 defaultdict(, {'b': {'king': 1, 'pawn': 3, 'bishop': 1}, 'w': {'king': 1, 'rook': 1, 'queen': 1}}) 但我只想拥有字典。
  • @aurumpurum。 defaultdict 是 dict 的子类。如果你想得到一个普通的字典,你可以做counts = dict(counts),但这真的没有必要。你可以对一个默认字典做所有你可以对一个字典做的事情。唯一真正的区别是,当您访问丢失的密钥时,它会为您创建它。
猜你喜欢
  • 2019-11-03
  • 2014-01-20
  • 2015-06-02
  • 2014-10-25
  • 1970-01-01
  • 2015-07-23
  • 2015-10-29
  • 2020-09-14
  • 2020-04-04
相关资源
最近更新 更多