如何做这个列表/字典理解
转此[("a", 1), ("b", 2), ("a", 3)]
进入这个
{
"a": [1, 3],
"b": [2]
}
我知道如何在for循环中执行此操作,我可以只使用一行来完成工作吗?
答案 0 :(得分:4)
一种简单的方法是使用简单的collections.defaultdict()
列表:
from collections import defaultdict
lst = [("a", 1), ("b", 2), ("a", 3)]
items = defaultdict(list)
for k, v in lst:
items[k].append(v)
print(items)
创造了:
defaultdict(<class 'list'>, {'a': [1, 3], 'b': [2]})
注意:如果您希望最终结果是普通字典,则可以包裹dict()
。
如果你真的想要一个班轮,你可以在词典理解中使用itertools.groupby()
:
>>> from itertools import groupby
>>> from operator import itemgetter
>>> lst = [("a", 1), ("b", 2), ("a", 3)]
>>> {k: list(map(itemgetter(1), g)) for k, g in groupby(sorted(lst, key=itemgetter(0)), key=itemgetter(0))}
{'a': [1, 3], 'b': [2]}
也可以更清晰地写成:
{k: [x[1] for x in g] for k, g in groupby(sorted(lst, key=itemgetter(0)), key=itemgetter(0))}
由于排序,上述解决方案具有O(NlogN)
复杂性,如果您想将类似项目组合在一起,则需要这样做。这比第一个defaultdict
解决方案(O(N)
)效率低,因为您只需要迭代列表一次。第一种解决方案更为可取,因为它更易于阅读,高效和可维护。
答案 1 :(得分:2)
就我个人而言,我认为在这里使用循环是一个简单的选项,但为了演示,您可以在此处定义一个继承自 collections.MutableMapping
的自定义类来实现您的目标。
import collections
class AutoListDict(collections.MutableMapping):
def __init__(self, values=()):
self.inner = collections.defaultdict(list)
for k, v in values:
self[k].append(v)
def __setitem__(self, k, v): self.inner[k] = v
def __getitem__(self, k):return self.inner[k]
def __delitem__(self, k_): del self.inner[k]
def __iter__(self): return iter(self.inner)
def __len__(self): return len(self.inner)
def __repr__(self): return str(dict(self.inner))
这会从您的输入值初始化 defaultdict
,因此不会覆盖附加到它的键。在操作中,您只需在元组数组上调用类构造函数:
>>> arr = [('a', 1), ('b', 2), ('a', 3)]
>>> AutoListDict(arr)
{'a': [1, 3], 'b': [2]}
或者如果你想要更类似于词典理解的东西:
>>> dct = AutoListDict((k, v) for k, v in arr)
>>> dct
{'a': [1, 3], 'b': [2]}