lst = [{'272': '4', '273': '4', '274': '4', '275': '5'}]
dct = {}
for k, v in lst[0].items():
if dct.get(v) is None:
dct.update({v: [k]})
else:
dct[v].append(k)
输出:
{'4': ['272', '273', '274'], '5': ['275']}
我还可以写一个嵌套理解:
dct = {v: [k for (k, v1) in lst[0].items() if v1 == v]
for (k, v) in lst[0].items()}
输出相同:
{'4': ['272', '273', '274'], '5': ['275']}**
但是我们可以尝试在字典理解中使用单个
for
循环来获得相同的结果吗?
你不可能在字典理解中一步完成同样的事情。您有效地反转了字典,但由于原始字典中没有一对一的映射,因此您需要聚合每个值的重复键。
问题中的列表是一个转移注意力的内容。我要用
d = {'272': '4', '273': '4', '274': '4', '275': '5'}
您可以采取几种方法。明智的做法是保持一个循环,但稍微简化一下。例如,您可以使用
collections.defaultdict
,它就像常规的 dict
,只不过它可以让您自动使用空值设置缺失的键:
from collections import defaultdict
result = defaultdict(list)
for k, v in d.items():
result[v].append(k)
如果您使用几个标准库函数,您可以为此编写一个推导式。一种方法是使用
itertools.groupby
,但这需要您先应用 sorted
:
from itertools import groupby
from operator import itemgetter
result = {k: list(map(itemgetter(0), vs))
for k, vs in groupby(sorted(d.items(),
key=itemgetter(1, 0)),
itemgetter(1))}
operator.itemgetter
的工作原理类似于 lambda x: x[0]
左右,但更快、更高效。
使用第二种解决方案,请注意,由于排序,时间复杂度从 O(n) 变为 O(n log n),并且为了获得“一行”而牺牲了很多易读性。
使用临时辅助字典的黑客:
dct = {v: h.setdefault(v, [k])
for h in [{}]
for k, v in lst[0].items()
if v not in h or h[v].append(k)}
这是反转一对多映射的一种方法。 它不需要排序。 一般来说,map_reduce 可以帮助解决很多问题。
import more_itertools as mit
d = {'272': '4', '273': '4', '274': '4', '275': '5'}
dict(mit.map_reduce(d.items(),
keyfunc=lambda el: el[1],
valuefunc=itemgetter(0),
))
# returns {'4': ['272', '273', '274'], '5': ['275']}