Python reverse / inverse a mapping (but with multiple values for each key)

二次信任 提交于 2019-12-18 15:50:00

问题


This is really a variation on this question, but not a duplicate:

Python reverse / invert a mapping

Given a dictionary like so:

mydict= { 'a': ['b', 'c'], 'd': ['e', 'f'] }

How can one invert this dict to get:

inv_mydict = { 'b':'a', 'c':'a', 'e':'d', 'f':'d' }

Note that values span uniquely under each key.

Note: I previously had syntax map = ... and dict = ... Reminder not to use map and dict as they are built-in functions, see excellent comments and answers below :)


回答1:


TL;DR

Use dictionary comprehension, like this

>>> my_map = { 'a': ['b', 'c'], 'd': ['e', 'f'] }
>>> {value: key for key in my_map for value in my_map[key]}
{'c': 'a', 'f': 'd', 'b': 'a', 'e': 'd'}

The above seen dictionary comprehension is functionally equivalent to the following looping structure which populates an empty dictionary

>>> inv_map = {}
>>> for key in my_map:
...     for value in my_map[key]:
...         inv_map[value] = key
... 
>>> inv_map
{'c': 'a', 'f': 'd', 'b': 'a', 'e': 'd'}

Note: Using map shadows the built-in map function. So, don't use that as a variable name unless you know what you are doing.


Other similar ways to do the same

Python 3.x

You can use dict.items, like this

>>> {value: key for key, values in my_map.items() for value in values}
{'c': 'a', 'f': 'd', 'b': 'a', 'e': 'd'}

We use items() method here, which would create a view object from the dictionary which would give key value pairs on iteration. So we just iterate over it and construct a new dictionary with the inverse mapping.

Python 2.x

You can use dict.iteritems like this

>>> {value: key for key, values in my_map.iteritems() for value in values}
{'c': 'a', 'b': 'a', 'e': 'd', 'f': 'd'}

We don't prefer items() method in 2.x, because it will return a list of key-value pairs. We don't want to construct a list just to iterate and construct a new dictionary. That is why we prefer iteritems(), which returns an iterator object which gives a key value pair on iteration.

Note: The actual equivalent of Python 3.x's items would be Python 2.x's viewitems method, which returns a view object. Read more about the view object in the official documentation, here.


iter* vs view* methods in Python 2.x

The main difference between iter* functions and view* functions in Python 2.x is that, the view objects reflect the current state of the dictionary. For example,

>>> d = {1: 2}
>>> iter_items = d.iteritems()
>>> view_items = d.viewitems()

now we add a new element to the dictionary

>>> d[2] = 3

If you try to check if (2, 3) (key-value pair) is in the iter_items, it will throw an error

>>> (2, 3) in iter_items
Traceback (most recent call last):
  File "<input>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

but view object will reflect the current state of the dictionary. So, it will work fine

>>> (2, 3) in view_items
True



回答2:


mp = { 'a': ['b', 'c'], 'd': ['e', 'f'] }

pm={}
for x in mp.iterkeys():
    for d in mp[x]:
        pm[d]=x

print pm

Output:

{'c': 'a', 'b': 'a', 'e': 'd', 'f': 'd'}

Note: a dictionary is an unordored data structure, so the result may not be ordered as you want it to be.



来源:https://stackoverflow.com/questions/29633848/python-reverse-inverse-a-mapping-but-with-multiple-values-for-each-key

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!