0

我有一本这样的字典:

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']})

比如这些问题:

Python中的Inverse Dict \\ 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

除了它不起作用之外,似乎这样的理解效率低下。有没有一种有效的、单一的方式来做到这一点?

4

3 回答 3

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']}

defaultdict

>>> 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']}
于 2014-01-27T07:33:37.510 回答
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
于 2014-01-28T01:23:36.913 回答
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)
于 2014-01-27T08:32:19.853 回答