Given a dictionary like so:
my_map = {'a': 1, 'b': 2} How can one invert this map to get:
inv_map = {1: 'a', 2: 'b'} 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()} my_map.items() works as wellAssuming that the values in the dict are unique:
Python 3:
dict((v, k) for k, v in my_map.items()) Python 2:
dict((v, k) for k, v in my_map.iteritems()) iteritems() will output, so it may be assumed that an arbitrary key will be assigned for a non-unique value, in a way that will be apparently reproducible under some conditions, but no so in general.iteritems() method and this approach will not work; use items() there instead as shown in the accepted answer. Also, a dictionary comprehension would make this prettier than calling dict.If the values in my_map aren't unique:
Python 3:
inv_map = {} for k, v in my_map.items(): inv_map[v] = inv_map.get(v, []) + [k] Python 2:
inv_map = {} for k, v in my_map.iteritems(): inv_map[v] = inv_map.get(v, []) + [k] inv_map.get(v, []) returns the already-added list if there is one, so the assignment doesn't reset to an empty list. setdefault would still be prettier, though.inv_map.setdefault(v, set()).add(k).my_map.items() instead of my_map.iteritems().setdefault by using a defaultdict: inv_map = collections.defaultdict(set) and then simply inv_map[v].add(k)To do this while preserving the type of your mapping (assuming that it is a dict or a dict subclass):
def inverse_mapping(f): return f.__class__(map(reversed, f.items())) f.__class__ because you already made the assumption that it is a dictionary. I would do it like this: dict(map(reversed, f.items()))items methodTry this:
inv_map = dict(zip(my_map.values(), my_map.keys())) (Note that the Python docs on dictionary views explicitly guarantee that .keys() and .values() have their elements in the same order, which allows the approach above to work.)
Alternatively:
inv_map = dict((my_map[k], k) for k in my_map) or using python 3.0's dict comprehensions
inv_map = {my_map[k] : k for k in my_map} Notice that this only works if the keys are unique
Another, more functional, way:
my_map = { 'a': 1, 'b':2 } dict(map(reversed, my_map.items())) filter and map should die and be subsumed into list comprehensions, not grow more variants".dict with other mapping types such as collections.OrderedDict or collections.defaultdictWe can also reverse a dictionary with duplicate keys using defaultdict:
from collections import Counter, defaultdict def invert_dict(d): d_inv = defaultdict(list) for k, v in d.items(): d_inv[v].append(k) return d_inv text = 'aaa bbb ccc ddd aaa bbb ccc aaa' c = Counter(text.split()) # Counter({'aaa': 3, 'bbb': 2, 'ccc': 2, 'ddd': 1}) dict(invert_dict(c)) # {1: ['ddd'], 2: ['bbb', 'ccc'], 3: ['aaa']} See here:
This technique is simpler and faster than an equivalent technique using
dict.setdefault().
dict(d_inv), since a dictionary has broader support than a less standard defaultdict. For example, some serializers (such as yaml.safe_dump) won't serialize a defaultdict while they will serialize a dict.This expands upon the answer by Robert, applying to when the values in the dict aren't unique.
class ReversibleDict(dict): # Ref: https://stackoverflow.com/a/13057382/ def reversed(self): """ Return a reversed dict, with common values in the original dict grouped into a list in the returned dict. Example: >>> d = ReversibleDict({'a': 3, 'c': 2, 'b': 2, 'e': 3, 'd': 1, 'f': 2}) >>> d.reversed() {1: ['d'], 2: ['c', 'b', 'f'], 3: ['a', 'e']} """ revdict = {} for k, v in self.items(): revdict.setdefault(v, []).append(k) return revdict The implementation is limited in that you cannot use reversed twice and get the original back. It is not symmetric as such. It is tested with Python 2.6. Here is a use case of how I am using to print the resultant dict.
If you'd rather use a set than a list, and there could exist unordered applications for which this makes sense, instead of setdefault(v, []).append(k), use setdefault(v, set()).add(k).
revdict.setdefault(v, set()).add(k)set. It's the intrinsic type that applies here. What if I want to find all keys where the values are not 1 or 2? Then I can just do d.keys() - inv_d[1] - inv_d[2] (in Python 3)For instance, you have the following dictionary:
my_dict = {'a': 'fire', 'b': 'ice', 'c': 'fire', 'd': 'water'} And you wanna get it in such an inverted form:
inverted_dict = {'fire': ['a', 'c'], 'ice': ['b'], 'water': ['d']} First Solution. For inverting key-value pairs in your dictionary use a for-loop approach:
# Use this code to invert dictionaries that have non-unique values inverted_dict = dict() for key, value in my_dict.items(): inverted_dict.setdefault(value, list()).append(key) Second Solution. Use a dictionary comprehension approach for inversion:
# Use this code to invert dictionaries that have unique values inverted_dict = {value: key for key, value in my_dict.items()} Third Solution. Use reverting the inversion approach (relies on the second solution):
# Use this code to invert dictionaries that have lists of values my_dict = {value: key for key in inverted_dict for value in my_map[key]} dict is reserved and shouldn't be used for variable namesmy_map isdictio()? Did you mean dict()?A case where the dictionary values is a set. Like:
some_dict = {"1":{"a","b","c"}, "2":{"d","e","f"}, "3":{"g","h","i"}} The inverse would like:
some_dict = {vi: k for k, v in some_dict.items() for vi in v} The output is like this:
{'c': '1', 'b': '1', 'a': '1', 'f': '2', 'd': '2', 'e': '2', 'g': '3', 'h': '3', 'i': '3'} Lot of answers but didn't find anything clean in case we are talking about a dictionary with non-unique values.
A solution would be:
from collections import defaultdict inv_map = defaultdict(list) for k, v in my_map.items(): inv_map[v].append(k) If initial dict my_map = {'c': 1, 'd': 5, 'a': 5, 'b': 10}
then, running the code above will give:
{5: ['a', 'd'], 1: ['c'], 10: ['b']} Combination of list and dictionary comprehension. Can handle duplicate keys
{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()} In addition to the other functions suggested above, if you like lambdas:
invert = lambda mydict: {v:k for k, v in mydict.items()} Or, you could do it this way too:
invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) ) I think the best way to do this is to define a class. Here is an implementation of a "symmetric dictionary":
class SymDict: def __init__(self): self.aToB = {} self.bToA = {} def assocAB(self, a, b): # Stores and returns a tuple (a,b) of overwritten bindings currB = None if a in self.aToB: currB = self.bToA[a] currA = None if b in self.bToA: currA = self.aToB[b] self.aToB[a] = b self.bToA[b] = a return (currA, currB) def lookupA(self, a): if a in self.aToB: return self.aToB[a] return None def lookupB(self, b): if b in self.bToA: return self.bToA[b] return None Deletion and iteration methods are easy enough to implement if they're needed.
This implementation is way more efficient than inverting an entire dictionary (which seems to be the most popular solution on this page). Not to mention, you can add or remove values from your SymDict as much as you want, and your inverse-dictionary will always stay valid -- this isn't true if you simply reverse the entire dictionary once.
dictresize, but this approach denies Python that possibility.If the values aren't unique, and you're a little hardcore:
inv_map = dict( (v, [k for (k, xx) in filter(lambda (key, value): value == v, my_map.items())]) for v in set(my_map.values()) ) Especially for a large dict, note that this solution is far less efficient than the answer Python reverse / invert a mapping because it loops over items() multiple times.
-1 because it still answers the question, just my opinion.This handles non-unique values and retains much of the look of the unique case.
inv_map = {v:[k for k in my_map if my_map[k] == v] for v in my_map.itervalues()} For Python 3.x, replace itervalues with values.
I am aware that this question already has many good answers, but I wanted to share this very neat solution that also takes care of duplicate values:
def dict_reverser(d): seen = set() return {v: k for k, v in d.items() if v not in seen or seen.add(v)} This relies on the fact that set.add always returns None in Python.
The solution is to loop over the start dictionary keys and value, and add them in reverse order to a new dictionary.
Example of reversing an english-to-spanish dictionary:
e2s = {'one': 'uno', 'two': 'dos', 'three': 'tres'} Plain old-fashioned clear Python code:
s2e = {} for english, spanish in e2s.items(): s2e[spanish] = english Dict comprehension:
>>> {spanish: english for english, spanish in e2s.items()} {'uno': 'one', 'dos': 'two', 'tres': 'three'} Functional approach:
>>> dict(map(reversed, s2e.items())) {'one': 'uno', 'two': 'dos', 'three': 'tres'} Functional approach with the operator module:
>>> dict(map(itemgetter(1, 0), e2s.items())) {'uno': 'one', 'dos': 'two', 'tres': 'three'} A dictionary of lists can model a one-to-many relationships.
boy_knows_girl = {'al': ['amy', 'sue'], 'bo': ['sue', 'dee'], 'kip': ['daisy', 'dee'], 'mark': ['amy', 'daisy']} To model many-to-many relationships, the forward one-to-many dictionary should be reversed into a second one-to-many dictionary.
girl_knows_boy = {'amy': ['al', 'mark'], 'sue': ['al', 'bo'], 'dee': ['bo', 'kip'], 'daisy': ['kip', 'mark']} Plain old-fashioned clear Python code:
girl_knows_boy = {} for boy, girls in boy_knows_girl.items(): for girl in girls: if girl not in girl_knows_boy: girl_knows_boy[girl] = [] girl_knows_boy[girl].append(boy) Simplify with dict.setdefault:
girl_knows_boy = {} for boy, girls in boy_knows_girl.items(): for girl in girls: girl_knows_boy.setdefault(girl, []).append(boy) Simplify more with collections.defaultdict:
from collections import defaultdict girl_knows_boy = defaultdict(list) for boy, girls in boy_knows_girl.items(): for girl in girls: girl_knows_boy[girl].append(boy) Relationship tuples with multiple fields are modeled as a list of tuples:
data = [('bob', 'male', 'sorbonne', 35), ('amy', 'female', 'oxford', 30), ('sue', 'female', 'sapienza', 25), ('mark', 'male', 'oxford', 35), ('bo', 'male', 'harvard', 25), ('dee', 'female', 'sorbonne', 30), ('daisy', 'female', 'stanford', 25), ('al', 'male', 'stanford', 40),] Unsurprisingly, the preferred tool designed for querying this data is a relational database such as sqlite3.
import sqlite3 conn = sqlite3.connect(':memory:') conn.execute('CREATE TABLE Cohort (name text, gender text, school text, age integer)') conn.executemany('INSERT INTO Cohort VALUES (?, ?, ?, ?)', data) Once loaded, forward and reverse lookups between any of the fields are implemented with simple queries:
conn.execute('SELECT name, age FROM Cohort WHERE gender="male"').fetchall() conn.execute('SELECT gender, age FROM Cohort WHERE school="stanford"').fetchall() conn.execute('SELECT school, gender FROM Cohort WHERE age=30').fetchall() Those queries can be made to run fast if the essential fields are in an index:
conn.execute('CREATE INDEX FastIndex ON Cohort ("gender", "school", "age")') This is a pretty popular question with two pages of different answers. So I decided to profile different approaches.
Here the most popular solutions:
def swap_loop(mock_dict): return dict((v,k) for k,v in mock_dict.items()) def swap_map(mock_dict): return dict(map(reversed, mock_dict.items())) def swap_map_lambda(mock_dict): return dict(map(lambda x: x[::-1], mock_dict.items())) def swap_slice(mock_dict): return {mock_dict[i]:i for i in mock_dict} def swap_zip(mock_dict): return dict(zip(mock_dict.values(), mock_dict.keys())) And results of profiling:
ncalls tottime percall cumtime percall filename:lineno(function) 1 0.128 0.128 0.247 0.247 script.py:34(swap_loop) 1 0.019 0.019 0.019 0.019 script.py:37(swap_map) 1 0.130 0.130 0.256 0.256 script.py:40(swap_map_lambda) 1 0.005 0.005 0.005 0.005 script.py:43(swap_slice) 1 0.003 0.003 0.003 0.003 script.py:46(swap_zip) As you can see zip approach is the fastest, any way result contains only unique keys (result has less length).
Full code and the results here
Function is symmetric for values of type list; Tuples are coverted to lists when performing reverse_dict(reverse_dict(dictionary))
def reverse_dict(dictionary): reverse_dict = {} for key, value in dictionary.iteritems(): if not isinstance(value, (list, tuple)): value = [value] for val in value: reverse_dict[val] = reverse_dict.get(val, []) reverse_dict[val].append(key) for key, value in reverse_dict.iteritems(): if len(value) == 1: reverse_dict[key] = value[0] return reverse_dict Since dictionaries require one unique key within the dictionary unlike values, we have to append the reversed values into a list of sort to be included within the new specific keys.
def r_maping(dictionary): List_z=[] Map= {} for z, x in dictionary.iteritems(): #iterate through the keys and values Map.setdefault(x,List_z).append(z) #Setdefault is the same as dict[key]=default."The method returns the key value available in the dictionary and if given key is not available then it will return provided default value. Afterward, we will append into the default list our new values for the specific key. return Map Fast functional solution for non-bijective maps (values not unique):
from itertools import imap, groupby def fst(s): return s[0] def snd(s): return s[1] def inverseDict(d): """ input d: a -> b output : b -> set(a) """ return { v : set(imap(fst, kv_iter)) for (v, kv_iter) in groupby( sorted(d.iteritems(), key=snd), key=snd ) } In theory this should be faster than adding to the set (or appending to the list) one by one like in the imperative solution.
Unfortunately the values have to be sortable, the sorting is required by groupby.
n elements in the original dict, your approach has O(n log n) time complexity due to the need to sort the dict's items, whereas the naive imperative approach has O(n) time complexity. For all I know your approach may be faster up until absurdly large dicts in practice, but it certainly isn't faster in theory.def invertDictionary(d): myDict = {} for i in d: value = d.get(i) myDict.setdefault(value,[]).append(i) return myDict print invertDictionary({'a':1, 'b':2, 'c':3 , 'd' : 1}) This will provide output as : {1: ['a', 'd'], 2: ['b'], 3: ['c']}
dict.items (or iteritems in Python 2) is more efficient than extracting each value separately while iterating keys. Also, you have added no explanation to an answer which duplicates others.A lambda solution for current python 3.x versions:
d1 = dict(alice='apples', bob='bananas') d2 = dict(map(lambda key: (d1[key], key), d1.keys())) print(d2) Result:
{'apples': 'alice', 'bananas': 'bob'} This solution does not check for duplicates.
Some remarks:
for loop. It also avoids using a list comprehension for those who are bad at math ;-)Taking up the highly voted answer starting If the values in my_map aren't unique:, I had a problem where not only the values were not unique, but in addition, they were a list, with each item in the list consisting again of a list of three elements: a string value, a number, and another number.
Example:
mymap['key1'] gives you:
[('xyz', 1, 2), ('abc', 5, 4)] I wanted to switch only the string value with the key, keeping the two number elements at the same place. You simply need another nested for loop then:
inv_map = {} for k, v in my_map.items(): for x in v: # with x[1:3] same as x[1], x[2]: inv_map[x[0]] = inv_map.get(x[0], []) + [k, x[1:3]] Example:
inv_map['abc'] now gives you:
[('key1', 1, 2), ('key1', 5, 4)] This works even if you have non-unique values in the original dictionary.
def dict_invert(d): ''' d: dict Returns an inverted dictionary ''' # Your code here inv_d = {} for k, v in d.items(): if v not in inv_d.keys(): inv_d[v] = [k] else: inv_d[v].append(k) inv_d[v].sort() print(f"{inv_d[v]} are the values") return inv_d