【问题标题】:list to dict with a group by on first value列表以根据第一个值进行分组
【发布时间】:2022-01-07 13:42:34
【问题描述】:

有什么技巧可以轻松地将列表转换为具有这种特定格式的字典吗?我一直无法这样做。

来自:

a = [
    ('A', 'B', 8),
    ('A', 'D', 10),
    ('A', 'E', 12),
    ('B', 'C', 6),
    ('B', 'F', 12),
    ('C', 'F', 8),
    ('D', 'E', 10),
    ('D', 'G', 30),
    ('E', 'F', 10),
    ('F', 'G', 12)
]

到:

b = {
    "A": {"B": 8, "D": 10, "E": 12},
    "B": {"C": 6, "F": 12},
    "C": {"F": 8},
    "D": {"E": 10, "G": 30},
    "E": {"F": 10},
    "F": {"G": 12}
}

提前感谢您的提示

【问题讨论】:

  • 你有没有尝试过什么?看起来很简单。遍历列表,根据需要在该键处创建字典,更新字典...

标签: python list dictionary data-structures


【解决方案1】:

使用集合模块中的defaultdict

from collections import defaultdict

b = defaultdict(dict)
for k, k1, v in a:
    b[k].update({k1: v})

输出:

>>> b
defaultdict(dict,
            {'A': {'B': 8, 'D': 10, 'E': 12},
             'B': {'C': 6, 'F': 12},
             'C': {'F': 8},
             'D': {'E': 10, 'G': 30},
             'E': {'F': 10},
             'F': {'G': 12}})

没有defaultdict的替代版本:

b = {}
for k, k1, v in a:
    t = b.setdefault(k, {})
    t[k1] = v

【讨论】:

  • 这很有趣。我们需要 defaultdict 因为首先需要有一个空白字典才能更新?
  • @RichardKYu。对,就是这样。避免使用条件语句来检查条目是否已经存在。
  • @RichardKYu。其实你可以很方便的用dict的setdefault方法替换defaultdictt 是每个条目的嵌套字典 k 就像 {'A': {}} t
  • 我建议不要使用b[k].update({k1: v}),而是使用b[k][k1] = v
  • @Stef。我暂时使用t 来更好地理解机制并说明我上面的评论:) 但你是完全正确的。我也更喜欢单行版本:)
【解决方案2】:

循环列表,检查键是否在字典中。如果是,则添加到该键的字典中。如果不是,则创建密钥字典:

a = [
    ('A', 'B', 8),
    ('A', 'D', 10),
    ('A', 'E', 12),
    ('B', 'C', 6),
    ('B', 'F', 12),
    ('C', 'F', 8),
    ('D', 'E', 10),
    ('D', 'G', 30),
    ('E', 'F', 10),
    ('F', 'G', 12)
]

final_list = {}
for item in a:
    if item[0] in final_list.keys():
        final_list[item[0]][item[1]] = item[2]
    else:
        final_list[item[0]] = {item[1]: item[2]}
print(final_list)

【讨论】:

  • 您可以将for item in a: 替换为for key1,key2,value in a:。那么复杂的final_list[item[0]][item[1]] = item[2]就变成了简单的final_list[key1][key2] = value
【解决方案3】:

如果第一级键按分组顺序,您可以在字典理解中使用 itertools 中的 groupby:

from itertools import groupby

d = { k:{c:n for _,c,n in v} for k,v in groupby(a,key=lambda t:t[0]) }

print(d)

{'A': {'B': 8, 'D': 10, 'E': 12}, 
 'B': {'C': 6, 'F': 12}, 
 'C': {'F': 8}, 
 'D': {'E': 10, 'G': 30}, 
 'E': {'F': 10}, 
 'F': {'G': 12}}

【讨论】:

  • 请注意它仅在因为列表已按第一个键排序时才有效。试试import random; random.shuffle(a)。你必须使用groupby(sorted(a, key=lambda t: t[0]), key=lambda t: t[0])
【解决方案4】:

这是一个适合初学者的代码。

  1. 我们解压元组并将值放入单个变量中
  2. 如果键已经在dic 中,则表示字典已经存在,我们只需添加另一对即可。
  3. 否则,我们在dic 中创建一个新的键值对,其中的值是一个字典。
list = [
    ('A', 'B', 8),
    ('A', 'D', 10),
    ('A', 'E', 12),
    ('B', 'C', 6),
    ('B', 'F', 12),
    ('C', 'F', 8),
    ('D', 'E', 10),
    ('D', 'G', 30),
    ('E', 'F', 10),
    ('F', 'G', 12)
]

dic = {}

for tuple in list:
    key, element, num = tuple
    if key in dic:
        dic[key][element] = num
    else:
        dic[key] = {element: num}

for k, v in dic.items():
    print(f"{k}: {v}")


输出:

{
    "A": {"B": 8, "D": 10, "E": 12},
    "B": {"C": 6, "F": 12},
    "C": {"F": 8},
    "D": {"E": 10, "G": 30},
    "E": {"F": 10},
    "F": {"G": 12}
}

【讨论】:

  • 这很好,除非您建议使用 tuplelist 作为变量名。但是tuplelist 已经是内置类的名称,隐藏内置类的名称是一个非常糟糕的习惯。
猜你喜欢
  • 1970-01-01
  • 2018-06-16
  • 1970-01-01
  • 2019-05-05
  • 1970-01-01
  • 2020-11-10
  • 2017-01-02
  • 1970-01-01
  • 2020-11-02
相关资源
最近更新 更多