[英]pythonic way to reverse a dict where values are lists?
我有一本看起來像這樣的字典:
letters_by_number = {
1: ['a', 'b', 'c', 'd'],
2: ['b', 'd'],
3: ['a', 'c'],
4: ['a', 'd'],
5: ['b', 'c']
}
我想把它倒過來看起來像這樣:
numbers_by_letter = {
'a': [1, 3, 4],
'b': [1, 2, 5],
'c': [1, 3, 5],
'd': [1, 2, 4]
}
我知道我可以通過遍歷 (key, value) 到letters_by_number
、遍歷value
(這是一個列表)並將 (val, key) 添加到字典中的列表來做到這一點。 這很麻煩,我覺得必須有一種更“pythonic”的方式來做到這一點。 有什么建議么?
這非常適合collections.defaultdict
:
>>> from collections import defaultdict
>>> numbers_by_letter = defaultdict(list)
>>> for k, seq in letters_by_number.items():
... for letter in seq:
... numbers_by_letter[letter].append(k)
...
>>> dict(numbers_by_letter)
{'a': [1, 3, 4], 'b': [1, 2, 5], 'c': [1, 3, 5], 'd': [1, 2, 4]}
請注意,您實際上並不需要最終的dict()
調用(一個defaultdict
已經為您提供了您可能想要的行為),但我將它包含在這里是因為您的問題的結果是類型dict
。
使用setdefault :
letters_by_number = {
1: ['a', 'b', 'c', 'd'],
2: ['b', 'd'],
3: ['a', 'c'],
4: ['a', 'd'],
5: ['b', 'c']
}
inv = {}
for k, vs in letters_by_number.items():
for v in vs:
inv.setdefault(v, []).append(k)
print(inv)
Output
{'a': [1, 3, 4], 'b': [1, 2, 5], 'c': [1, 3, 5], 'd': [1, 2, 4]}
dict
的(微不足道的)子類將使這非常容易:
class ListDict(dict):
def __missing__(self, key):
value = self[key] = []
return value
letters_by_number = {
1: ['a', 'b', 'c', 'd'],
2: ['b', 'd'],
3: ['a', 'c'],
4: ['a', 'd'],
5: ['b', 'c']
}
numbers_by_letter = ListDict()
for key, values in letters_by_number.items():
for value in values:
numbers_by_letter[value].append(key)
from pprint import pprint
pprint(numbers_by_letter, width=40)
Output:
{'a': [1, 3, 4],
'b': [1, 2, 5],
'c': [1, 3, 5],
'd': [1, 2, 4]}
這是使用 dict 理解的解決方案,無需在循環中添加列表元素。 通過將所有列表連接在一起來構建一組鍵,然后使用列表推導構建每個列表。 為了更高效,我首先構建了另一個包含集合而不是列表的字典,因此k in v
是 O(1) 操作。
from itertools import chain
def invert_dict_of_lists(d):
d = { i: set(v) for i, v in d.items() }
return {
k: [ i for i, v in d.items() if k in v ]
for k in set(chain.from_iterable(d.values()))
}
嚴格來說,Python 3 的現代版本中的字典保留了插入鍵的順序。這會產生一個結果,即鍵按照它們在列表中出現的順序; 不像你的例子中的字母順序。 如果您確實希望鍵按排序順序, for k in set(...)
更改為for k in sorted(set(...))
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.