簡體   English   中英

pythonic方式來反轉一個值是列表的字典?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM