具有Dict理解的Tuple到Dict Dict的元组

时间:2019-02-04 16:26:30

标签: python python-3.x

是否可以像这样转换一个元组的元组:

l = (("a","aa",1),("a","bb",2),("a","cc",1),("b","ee",9),("b","gg",2))

像这样的字典:

{"a":{"aa":1,"bb":2,"cc":1}  "b": {"ee":9,"gg":2}}

使用这样的字典理解:

r = {? for a,b,c in l}

5 个答案:

答案 0 :(得分:5)

您可以将groupby与字典理解结合使用:

from itertools import groupby
from operator import itemgetter

l = (("a", "aa", 1), ("a", "bb", 2), ("a", "cc", 1), ("b", "ee", 9), ("b", "gg", 2))

first = itemgetter(0)
result = {key: {inner: value for _, inner, value in groups} for key, groups in groupby(l, key=first)}

print(result)

输出

{'b': {'gg': 2, 'ee': 9}, 'a': {'cc': 1, 'bb': 2, 'aa': 1}}

如@ juanpa.arrivillaga所述,如果输入未按每个元组的第一个元素进行排序,则需要对其进行排序,为此,您可以执行以下操作:l = sorted(l, key=first),然后再使用字典理解。

答案 1 :(得分:2)

使用itertools.groupby

from itertools import groupby

l = (("a","aa",1),("a","bb",2),("a","cc",1),("b","ee",9),("b","gg",2))

print({x: {z[1]: z[2] for z in y} for x, y in groupby(sorted(l, key=lambda x: x[0]), lambda x: x[0])})
# {'a': {'aa': 1, 'bb': 2, 'cc': 1}, 'b': {'ee': 9, 'gg': 2}}

答案 2 :(得分:0)

在我看来,Daniel Mesejo的答案很明确。该答案基于groupby,但从功能上讲,groupbyreduce的一种形式。因此,出于多样性考虑,我将在这里提供functools.reduce(也使用defaultdict)的解决方案:

>>> from functools import reduce
>>> from collections import defaultdict
>>> l = (("a","aa",1),("a","bb",2),("a","cc",1),("b","ee",9),("b","gg",2))
>>> def update_and_return(acc, up):
...     acc[up[0]][up[1]] = up[2]
...     return acc
... 
>>> reduce(update_and_return, l, defaultdict(dict))
defaultdict(<type 'dict'>, {'a': {'aa': 1, 'cc': 1, 'bb': 2}, 'b': {'ee': 9, 'gg': 2}})

即使这不是字典理解解决方案,但我希望它可以为希望了解回答该问题所需的计算的人提供更多上下文。

答案 3 :(得分:0)

您是否喜欢滥用ptr = &a; printf("%d\n", **ptr); 而不是目的?老实说,我会在这里使用其他答案,但这也是这样做的另一种方式。

built-ins

使用from collections import defaultdict d = defaultdict(dict) any(d[x[0]].update({x[1]: x[-1]}) for x in l) print(d) defaultdict(dict, {'a': {'aa': 1, 'bb': 2, 'cc': 1}, 'b': {'ee': 9, 'gg': 2}}) 将返回一个any,这显然不是此处的预期目的,因此,我为什么建议列出其他答案。

答案 4 :(得分:0)

这是我可能会使用的,因为我觉得它相当可读...

l = (("a","aa",1),("a","bb",2),("a","cc",1),("b","ee",9),("b","gg",2))
from collections import defaultdict

d = defaultdict(dict)

for a,b,c in l:
    d[a][b]=c


print(d)

defaultdict(dict, {'a': {'aa': 1, 'bb': 2, 'cc': 1}, 'b': {'ee': 9, 'gg': 2}})

我对其他我喜欢的解决方案(groupby)做了一个粗略的基准测试:

l = (("a","aa",1),("a","bb",2),("a","cc",1),("b","ee",9),("b","gg",2))
from collections import defaultdict
def dd():
    d = defaultdict(dict)
    for a,b,c in l:
        d[a][b]=c


def gb():
    {x: {z[1]: z[2] for z in y} for x, y in groupby(sorted(l, key=lambda x: x[0]), lambda x: x[0])}

def gb2():
    first = itemgetter(0)
    result = {key: {inner: value for _, inner, value in groups} for key, groups in groupby(l, key=first)}

%timeit dd()
%timeit gb()
%timeit gb2()

683 ns ± 1.33 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
2.11 µs ± 129 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
1.38 µs ± 29.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

(您会看到itemgetter的附加值与必须进行另一次导入的比较,groupby还希望输入经过排序,因此对于较大的列表,性能损失甚至会更糟...)