有没有更简洁的方法将一系列 (key,value) 元组转换成 {key:[value,..],..} 字典?

3
我有一个元组序列itemList,格式为(key, value),我想将列表中的项目转换为格式为{key : [value, ..], ..}dict。一个特定的key值可能会在itemList中多次出现,并且具有匹配或新的value,我也想记录这些值(这就是为什么简单地使用dict(itemList)不起作用的原因)。
我正在使用Python2.7.9,并寻找缩小此代码的方法:
newDict = dict()
for k,v in itemList:  # itemList contains the tuples described above.
    if k in newDict:
        newDict[k].append(v)
    else:
        newDict[k] = [v]

我尝试使用map()list-comprehensionsnewDict.update(..)结合使用,但都没有达到预期效果。
我查看了这个类似的问题,但是我的输入格式和期望的输出格式有很大的区别。
(对于那些想知道“为什么要更改这个完全可接受的代码?”的人:我感兴趣的是寻找使用Python内置函数和模块的替代方法,更多地是作为学术练习,而不是故意避免一些功能性和易懂的东西。)
2个回答

4
您可以使用 dict.setdefault 来缩短您的代码,例如:
newDict = {}
for k, v in itemList:
    newDict.setdefault(k, []).append(v)
setdefault会在字典中查找键,如果没有找到,则将第二个参数赋值给它并返回。
如果在字典中找到了键,则简单地返回相应的值。
另外,您可以使用collections.defaultdict,如下所示。
from collections import defaultdict

result = defaultdict(list)
for k, v in itemList:
    result[k].append(v)

这类似于使用setdefault的方法。如果在字典中找不到键,则会调用传递给defaultdict构造函数的函数来创建一个新值。


这些方法真的很有趣!我之前用过 dict.get(SomeThing, dict()) 这种方式,但我没注意到 setdefault!+1 我也应该看看 collections,因为我经常看到它,但已经拖了一段时间了... - Augusta

0

这一行代码可以替代之前的代码,但是阅读起来要困难得多。而且它可能也不太快,因为它需要多次迭代itemList

newDict = dict((k, [_v for _k,_v in itemList if _k == k]) for k in set(i[0] for i in itemList))


2
这具有二次运行时复杂度。如果itemList很大,它将变得非常低效。 - thefourtheye
@thefourtheye 我发现在另一个迭代器内运行列表推导式会非常耗费资源,是的...这只是我找到的一种解决方案。不得不承认,这并不是一个好的替代品。XD - Augusta
@thefourtheye 这个修订版本只迭代唯一的 itemList 键(在找到它们后),而不是每个 itemList 项。虽然不是最好的,但已经好了很多。 - Augusta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接