【问题标题】:Populating a Nested Dictionary填充嵌套字典
【发布时间】:2018-01-20 15:25:45
【问题描述】:

我有一个很长的嵌套元组列表,我正在迭代并以某种方式追加一个空字典:

dict = {}

会这样填充:

dict = {a: {b:1,5,9,2,3}, b: {c:7,4,5,6,2,4}, c: {b:3,13,2,4,2}... }

迭代将检查嵌套字典是否存在,如果存在,则追加该值,否则,创建嵌套字典。我糟糕的尝试看起来像这样:

longlist = [(1,(a,b)),(2,(b,c)), (3,(c,b)) ... ]
dict = {}
    for each in longlist:
        if dict[each[1][0]][each[1][1]]:
            dict[each[1][0]][each[1][1]].append(each[0])
        else:
            dict[each[1][0]] = {}
            dict[each[1][0]][each[1][1]] = each[0]

我的方法的问题是迭代失败,因为字典开始时是空的,或者嵌套的父级在字典中不存在。对我来说越来越复杂了。我无法在网上找到很多关于如何处理嵌套字典的信息,所以我认为应该可以在这里提问。

【问题讨论】:

  • dict = {a: {b:1,5,9,2,3}, b: {c:7,4,5,6,2,4}, c: {b:3,13,2,4,2}... }:你能解释一下它是如何由这样的东西形成的吗:[(1,(a,b)),(2,(b,c)), (3,(c,b))]?如果您能明确我可以提供解决方案。
  • 看看(1,(a,b)),迭代会创建a:{}b:{},变成a:{b:{}}。然后将附加 1,从而产生 a:{b:{1}}。该过程随着数值的填充而重复。我在示例中放置了一个不连续的数字,因为这就是现实世界版本的结果,我正在处理数百个数据:/
  • @JosephKim 添加了进一步的改进。希望对您有所帮助!

标签: python list dictionary nested tuples


【解决方案1】:

这是使用collections.defaultdict的解决方案

import random
import collections
choices = ['a', 'b', 'c', 'd', 'e', 'f']

longlist = []
for i in range(1, 101):
    longlist.append((i, tuple(random.sample(choices, 2))))

print longlist

final = collections.defaultdict(lambda: collections.defaultdict(list))

for value, (key1, key2) in longlist:
    final[key1][key2].append(value)


print final

一般来说,我更改代码的方式是首先确保嵌套字典存在(collections.defaultdict 会为您处理这个问题),然后总是追加一次。

类似

for value (key1, key2) in longlist:
    if not your_dict.get(key1):
        your_dict[key1] = {}
    if not your_dict.get(key1).get(key2):
        your_dict[key1][key2] = []
    your_dict[key1][key2].append(value)

也不是 for line vs "for each ..." 这是解包迭代中的项目。你也可以这样做

for value, keys in longlist:

但由于键也是可迭代的,如果将其包装在括号中,您也可以将其解包。

【讨论】:

  • 我发现 collections.defaultdict 实际上是检查现有字典的更好方法。通过一些调整,我实际上能够考虑更长版本的长名单:longlist = [(1,(a,b,d,e,...)),(2,(b,c,a,f,...)), (3,(c,b,a,f,...)) ... ]
【解决方案2】:

无需深入研究您正在尝试做的事情,您可以重写您的if 语句以如果键不存在则抛出错误:

if dict_.get(each[1][0], {}).get(each[1][1], None):
    dict_[each[1][0]][each[1][1]].append(each[0])

dict.get 是一个非常有用的函数,如果给定的键不存在,它会返回一个特定的默认值。

此外,您似乎希望存在一个列表。在else 块中,您的意思是这样做吗?

dict_[each[1][0]][each[1][1]] = [each[0]]

这将创建一个包含单个元素的列表,所以现在dict[...][...].append(...) 可以工作了。

我还建议不要使用dict 来命名您的变量。它隐藏了内置类。

进一步的改进可能包括在 for 循环的头部解包项目,因此您不必执行 each[0]each[1] 等操作。你可以使用类似的东西:

for idx, pair in longlist:
    x, y = pair # unpack each pair now
    ...

完整列表:

dict_ = {}
for idx, pair in longlist:
    x, y = pair
    if dict_.get(x, {}).get(y, None):
        dict_[x][y].append(idx)

    else:
        dict_[x] = {y : [idx] }

这比以前更具可读性。

【讨论】:

  • 效果很好。 get 函数正是我想要的。我已经接受了这个作为我的答案。谢谢!
  • @JosephKim 很高兴我能帮上忙。干杯!
猜你喜欢
  • 2016-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-06
  • 1970-01-01
  • 2017-08-31
  • 1970-01-01
  • 2020-06-08
相关资源
最近更新 更多