Reverse / invert a dictionary mapping

前端 未结 26 2214
一整个雨季
一整个雨季 2020-11-21 11:47

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\'         


        
相关标签:
26条回答
  • 2020-11-21 12:03

    Try this for python 2.7/3.x

    inv_map={};
    for i in my_map:
        inv_map[my_map[i]]=i    
    print inv_map
    
    0 讨论(0)
  • 2020-11-21 12:03
      def reverse_dictionary(input_dict):
          out = {}
          for v in input_dict.values():  
              for value in v:
                  if value not in out:
                      out[value.lower()] = []
    
          for i in input_dict:
              for j in out:
                  if j in map (lambda x : x.lower(),input_dict[i]):
                      out[j].append(i.lower())
                      out[j].sort()
          return out
    

    this code do like this:

    r = reverse_dictionary({'Accurate': ['exact', 'precise'], 'exact': ['precise'], 'astute': ['Smart', 'clever'], 'smart': ['clever', 'bright', 'talented']})
    
    print(r)
    
    {'precise': ['accurate', 'exact'], 'clever': ['astute', 'smart'], 'talented': ['smart'], 'bright': ['smart'], 'exact': ['accurate'], 'smart': ['astute']}
    
    0 讨论(0)
  • 2020-11-21 12:04

    We 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 ffffd aaa bbb ccc aaa' 
    c = Counter(text.split()) # Counter({'aaa': 3, 'bbb': 2, 'ccc': 2, 'ffffd': 1})
    dict(invert_dict(c)) # {1: ['ffffd'], 2: ['bbb', 'ccc'], 3: ['aaa']}  
    

    See here:

    This technique is simpler and faster than an equivalent technique using dict.setdefault().

    0 讨论(0)
  • 2020-11-21 12:05

    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.

    0 讨论(0)
  • 2020-11-21 12:05

    Not something completely different, just a bit rewritten recipe from Cookbook. It's futhermore optimized by retaining setdefault method, instead of each time getting it through the instance:

    def inverse(mapping):
        '''
        A function to inverse mapping, collecting keys with simillar values
        in list. Careful to retain original type and to be fast.
        >> d = dict(a=1, b=2, c=1, d=3, e=2, f=1, g=5, h=2)
        >> inverse(d)
        {1: ['f', 'c', 'a'], 2: ['h', 'b', 'e'], 3: ['d'], 5: ['g']}
        '''
        res = {}
        setdef = res.setdefault
        for key, value in mapping.items():
            setdef(value, []).append(key)
        return res if mapping.__class__==dict else mapping.__class__(res)
    

    Designed to be run under CPython 3.x, for 2.x replace mapping.items() with mapping.iteritems()

    On my machine runs a bit faster, than other examples here

    0 讨论(0)
  • 2020-11-21 12:06

    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.

    0 讨论(0)
提交回复
热议问题