我有这样的字典:
dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
并想要像这样的逆:
dict2 = dict({1:['a','b','c'], 2:['a','b','c'], 3:['a','b'], 4:['b']})
喜欢这些问题:
Inverse Dict in Python \\ In-place dictionary inversion in Python
但我想用非唯一键来做,我不想进行就地转换。我有一些代码工作,但我想知道是否有字典理解方式这样做。
from collections import defaultdict
dict2 = defaultdict(list)
for i in dict1:
for j in dict1[i]:
dict2[j].append(i)
我尝试了这个,但它只适用于唯一的映射。通过唯一,我的意思是“对于每个值,只有一个键列出值”。如此独特的映射:'1:[a],2:[b],3:[c] - > a:[1],b:[2],c:[3]'VS非唯一映射'1:[a],2:[a,b],3:[b,c] - > a:[1,2],b:[2,3],c:[3]'
dict2 = {j: i for i in dict1 for j in dict1[i]}
我认为必须是这样的:
dict2 = {j: [i for i in dict1 if j in dict1[i]] for j in dict1[i]} # I know this doesn't work
除了它不起作用之外,似乎这样的理解是低效的。这样做是否有效率的单线方式?
答案 0 :(得分:4)
标准dict
:
>>> dict2 = {}
>>> for key, values in dict1.items():
... for value in values:
... dict2.setdefault(value, []).append(key)
...
>>> dict2
{1: ['a', 'c', 'b'], 2: ['a', 'c', 'b'], 3: ['a', 'b'], 4: ['b']}
>>> dict2 = defaultdict(list)
>>> for key, values in dict1.items():
... for value in values:
... dict2[value].append(key)
...
>>> dict2
{1: ['a', 'c', 'b'], 2: ['a', 'c', 'b'], 3: ['a', 'b'], 4: ['b']}
答案 1 :(得分:3)
根据Vroomfondel的回答,我找到了答案:
dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = {item: [key for key in dict1 if item in dict1[key]] for value in dict1.values() for item in value}
这不是最快的,但它是一个单线,并不是最慢的选项!
from timeit import timeit
methods = [['Vroomfondel1', '''from collections import defaultdict
import itertools
dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = defaultdict(list)
for k,v in itertools.chain.from_iterable([itertools.product(vals,key) for key,vals in dict1.items()]):
dict2[k].append(v)'''],
['Vroomfondel2', '''from collections import defaultdict
import itertools
dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = defaultdict(list)
[dict2[k].append(v) for k,v in itertools.chain.from_iterable([itertools.product(vals,key) for key,vals in dict1.items()])]'''],
['***Vroomfondel2 mod', '''dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = {item: [key for key in dict1 if item in dict1[key]] for value in dict1.values() for item in value}'''],
['mhlester1', '''dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = {}
for key, values in dict1.items():
for value in values:
dict2.setdefault(value, []).append(key)'''],
['mhlester1 mod', '''from collections import defaultdict
dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = defaultdict(list)
for key, values in dict1.items():
for value in values:
dict2[value].append(key)'''],
['mhlester2', '''from collections import defaultdict
dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = defaultdict(list)
for key, values in dict1.items():
for value in values:
dict2[value].append(key)'''],
['initial', '''from collections import defaultdict
dict1 = {'a':[1,2,3], 'b':[1,2,3,4], 'c':[1,2]}
dict2 = defaultdict(list)
for i in dict1:
for j in dict1[i]:
dict2[j].append(i)''']
]
for method in methods:
print "% 15s" % (method[0]), '\t', timeit(method[1], number=10000)
打印出来:
Vroomfondel1 0.202519893646
Vroomfondel2 0.164724111557
***Vroomfondel2 mod 0.114083051682
mhlester1 0.0599339008331
mhlester1 mod 0.091933965683
mhlester2 0.0900268554688
initial 0.0953099727631
答案 2 :(得分:2)
作为一个单行(感谢mhlesters输入),但具有一般可读性(并且只能工作,因为dict2中的值是可变的,因此setdefault返回对它们的引用):
import itertools
[dict2.setdefault(k,[]).append(v) for k,v in itertools.chain.from_iterable([itertools.product(vals,[key]) for key,vals in dict1.items()])]
或者使用for循环:
import collections
import itertools
dict2=collections.defaultdict(list)
for k,v in itertools.chain.from_iterable([itertools.product(vals,[key]) for key,vals in dict1.items()]):
dict2[k].append(v)