Inverting a Dictionary with List Values

Inverting a dictionary with list values

I've tried around and you want to use val not in inverse but it can't be checked if a "list is in a dict". (val is a list)

For your code a simple change will do what you want:

def invert_dict(d): 
inverse = dict()
for key in d:
# Go through the list that is saved in the dict:
for item in d[key]:
# Check if in the inverted dict the key exists
if item not in inverse:
# If not create a new list
inverse[item] = [key]
else:
inverse[item].append(key)
return inverse

pythonic way to reverse a dict where values are lists?

This is well-suited for 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]}

Note that you don't really need the final dict() call (a defaultdict will already give you the behavior you probably want), but I included it here because the result from your question is type dict.

Inverting a dictionary with sets/lists as values

dict.fromkeys(d, set()) just creates one set and puts that in every dictionary entry. You need to create a new set for each entry:

inverse_dict = {k: set() for k in d}

Reverse / invert a dictionary mapping

Python 3+:

inv_map = {v: k for k, v in my_map.items()}

Python 2:

inv_map = {v: k for k, v in my_map.iteritems()}

How to reverse a dictionary (whose values are lists) in Python?

You can do it very simply like this:

newdict = {}
for key, value in olddict.items():
for string in value:
newdict.setdefault(string, []).append(key)

How can I flatten a dictionary with a list for values?

Use a dictionary comprehension with nested iteration:

>>> d = {
... "USA": ["US", "United States"],
... "SGP": ["JP", "Japan", "Singapore"]
... }
>>> {i: k for k, v in d.items() for i in v}
{'US': 'USA', 'United States': 'USA', 'JP': 'SGP', 'Japan': 'SGP', 'Singapore': 'SGP'}
  • k, v in d.items() -> k = "USA", ..., v = ["US", "United States"], ...
  • i in v -> i = "US", ...

hence:

  • {i: k ...} -> {"US": "USA", ...}

Python 3: How Do I Invert A Dictionary That Has A List As A Value

You can use a defaultdict to remove the else statement and to check if the key exists. If it doesn't exists an empty list will be created.

from pprint import pprint

summon_locations = {
"Solaire": ['Gargoyles', 'Gaping Dragon', "Ornstein/Smough"],
"Gotthard": ['Abyss Watchers', 'Pontiff Sulyvahn', "Grand Archives"],
"Lucatiel": ['Lost Sinner', 'Smelter Demon', 'Abyss Watchers'],
}

if __name__ == '__main__':
from collections import defaultdict

inverted = defaultdict(list)

for key, values in summon_locations.items():
for value in values:
inverted[value].append(key)

pprint(inverted)

Output

defaultdict(<class 'list'>,
{'Abyss Watchers': ['Gotthard', 'Lucatiel'],
'Gaping Dragon': ['Solaire'],
'Gargoyles': ['Solaire'],
'Grand Archives': ['Gotthard'],
'Lost Sinner': ['Lucatiel'],
'Ornstein/Smough': ['Solaire'],
'Pontiff Sulyvahn': ['Gotthard'],
'Smelter Demon': ['Lucatiel']})

Which is similar to the the one-liner

[inverted[value].append(key) for key, values in summon_locations.items() for value in values]

But one liners are not always better, in this case I would stay with the two for loops.

Invert a dictionary with list values in ansible

The playbook

- hosts: localhost
vars:
dict1:
host1: [tag1, tag2]
host2: [tag1]
tasks:
- set_fact:
dict2: "{{ dict2|default({})|combine({item: list_of_hosts}) }}"
loop: "{{ dict1.values()|flatten|unique }}"
vars:
list_of_hosts: "{{ dict1|
dict2items|
selectattr('value', 'contains', item)|
map(attribute='key')|
list }}"
- debug:
var: dict2

gives

  dict2:
tag1: [host1, host2]
tag2: [host1]

Optionally, use json_query

      vars:
list_of_hosts: "{{ dict1|dict2items|json_query(_query) }}"
_query: '[?value.contains(@, `{{ item }}`)].key'



Related Topics



Leave a reply



Submit