【问题标题】:Converting list of lists into a dictionary of dictionaries in Python将列表列表转换为Python中的字典字典
【发布时间】:2019-02-10 16:54:50
【问题描述】:

我正在尝试将列表数据结构的列表转换为字典字典。

列表定义如下:

l = [
  ['PP','Ear-rings', 'Holesovice', 2000],
  ['PP','Skirts', 'Holesovice', 1000],
  ['PP','Dresses', 'E-shop', 1500],
  ['BM','Butterfly', 'Holesovice', 1600]
]

我的目标是字典结构如下:

#{'PP' : {'Holesovice' : {'Ear-rings' : 2000, 'Skirts' : 1000},
#         'E-shop' : {'Dresses' : 1500}},
# 'BM' : {'Holesovice' : {'Butterfly' : 1600}}
#}

这段代码没有返回想要的输出:

labels_d = {}
items_d = {}
shops_d = {}

for index, row in enumerate(l):
  items_d[row[1]] = row[3]
  shops_d[row[2]] = items_d
  labels_d[row[0]] = shops_d

print(labels_d)

我发现一些帖子处理将列表转换为字典 herehere 但我没有让它按我想要的方式工作。是否有任何“干净”的方式来实现上面发布的结构?

【问题讨论】:

标签: python python-3.x list dictionary nested


【解决方案1】:

使用dict.setdefault(key, {}) 是创建固定深度嵌套字典的好方法。

l = [
  ['PP','Ear-rings', 'Holesovice', 2000],
  ['PP','Skirts', 'Holesovice', 1000],
  ['PP','Dresses', 'E-shop', 1500],
  ['BM','Butterfly', 'Holesovice', 1600]
]

d = {}

for tag, item, source, qty in l:
    d.setdefault(tag, {}).setdefault(source, {})[item] = qty 

输出

{'BM': {'Holesovice': {'Butterfly': 1600}},
 'PP': {'E-shop': {'Dresses': 1500},
        'Holesovice': {'Ear-rings': 2000, 'Skirts': 1000}}}

概括

通过构建一个嵌套字典类,可以使上述解决方案更通用,放弃具有固定深度的要求。

class NestedDict(dict):
    def __getitem__(self, item):
        if item not in self:
            self[item] = NestedDict()
        return super().__getitem__(item)

d = NestedDict()

for tag, item, source, qty in l:
    d[tag][source][item] = qty 

还要注意,类方法是创建的,因此它仅在键不存在时创建一个对象,而setdefault 方法在每次访问时都会创建一个空的dict

【讨论】:

  • 每次调用 setdefault 时都会看到一个新对象创建,这真的让我在脑海中磨磨蹭蹭,尽管这是一个非常好的解决方案。
  • @OlivierMelançon 他们只是表示NestedDict() 被调用,不管item 是否已经有一个值,这有点不雅。
  • @MadPhysicist 这在一般方法中已解决
  • 我知道解决方案,我相信你也是。我喜欢你原来的答案,因为它很简单。我的评论只是对setdefault 的普遍不满。如果有另一种方法接受可调用而不是预先构造的实例,那就太好了。
  • 我以前从未在 Python 讨论线程上发布过任何内容。也许现在是开始的好时机。我先看看能不能想出一个简单的实现。
【解决方案2】:

你可以使用无限嵌套的defaultdict技巧:

from collections import defaultdict

def nested_dict():
    return defaultdict(nested_dict)

nd = nested_dict()
for a, b, c, d in l:
    nd[a][c][b] = d

【讨论】:

  • 我也喜欢这个。如果你将nested_dict 设为类而不是工厂,我觉得会更整洁。
  • @OlivierMelançon 以如此整洁的方式在类中拥有递归逻辑当然是一个挑战。毕竟,defaultdict 构造函数的参数是默认的 factory ;-)
  • @schwobaseggl 这非常简单,因为工厂存储为实例参数。 class NestedDict(defaultdict): def __init__(self): self.default_factory = NestedDict
  • @OlivierMelançon 没错,我也喜欢这样。它当然提供了额外的见解。
  • 这个答案当然很好。但我确实认为重要的是要注意这与我非常相似但更准确的答案之间的区别。当你检查一个键 nd['key1']['key2']['key3'] 并且它不存在时,你会得到一个空字典 {},而在我的解决方案中你会得到 0。从概念上讲,它可能是相关的,您可能不期望 {}
【解决方案3】:

您可以使用collections.defaultdict 并进行迭代。在这种情况下,您可以精确地定义一个嵌套字典来反映您的数据结构。

from collections import defaultdict

L = [['PP','Ear-rings', 'Holesovice', 2000],
     ['PP','Skirts', 'Holesovice', 1000],
     ['PP','Dresses', 'E-shop', 1500],
     ['BM','Butterfly', 'Holesovice', 1600]]

d = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))

for code, item, shop, value in L:
    d[code][shop][item] = value

结果

defaultdict({'BM': defaultdict({'Holesovice': defaultdict(int, {'Butterfly': 1600})}),
             'PP': defaultdict({'E-shop': defaultdict(int, {'Dresses': 1500}),
                                'Holesovice': defaultdict(int,
                                {'Ear-rings': 2000, 'Skirts': 1000})})})

【讨论】:

  • 我花了一段时间才注意到它,但在字典底部返回 0 既微妙又整洁
【解决方案4】:
def toNested1(l):
    def addKeyDict(map,key):    
        if key not in map:
            item = map[key] = {}
            return item            
        return map[key]

    zz = {}
    for a0,a1,a2,a3 in l :
        addKeyDict( addKeyDict( zz, a0) , a2 )[a1] = a3
    return zz

【讨论】:

    【解决方案5】:

    在这里发布一个编写新字典的非常简单的方法:

    如果列表的每一行中的项目不在对应的字典深度中,只需将键值对添加/附加到字典即可。

    代码:

    list = [
        ['PP','Ear-rings', 'Holesovice', 2000],
        ['PP','Skirts', 'Holesovice', 1000],
        ['PP','Dresses', 'E-shop', 1500],
        ['BM','Butterfly', 'Holesovice', 1600]
    ]
    
    dicta = {}
    for row in list:
        if row[0] not in dicta.keys():
            dicta[row[0]] = {row[2]:{row[1]:row[3]}}
            continue
        if row[2] not in dicta[row[0]].keys():
            dicta[row[0]][row[2]] = {row[1]:row[3]}
            continue
        if row[1] not in dicta[row[0]][row[2]].keys():
            dicta[row[0]][row[2]][row[1]] = row[3]
    
    print(dicta)
    

    输出:

    {'BM': {'Holesovice': {'Butterfly': 1600}},
     'PP': {'E-shop': {'Dresses': 1500},
            'Holesovice': {'Ear-rings': 2000, 'Skirts': 1000}}}
    

    【讨论】:

      猜你喜欢
      • 2015-07-23
      • 1970-01-01
      • 2017-04-23
      • 2021-10-13
      • 2014-07-28
      • 1970-01-01
      • 2012-07-12
      • 1970-01-01
      相关资源
      最近更新 更多