Python обратный / инвертировать отображение

Приведенный словарь выглядит так:

my_map = { 'a': 1, 'b':2 }

Как можно инвертировать эту карту, чтобы получить:

inv_map = { 1: 'a', 2: 'b' }

РЕДАКТОР ПРИМЕЧАНИЕ: map изменено на my_map, чтобы избежать конфликтов со встроенной функцией map. Некоторые комментарии могут быть затронуты ниже.

вопрос задан 27.01.2009
Brian M. Hunt
35082 репутация

29 ответов


  • 634 рейтинг

    Для Python 2. 7. x

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

    Для Python 3+:

    inv_map = {v: k for k, v in my_map.items()}
    
    ответ дан SilentGhost, с репутацией 182813, 27.01.2009
  • 160 рейтинг

    Предполагая, что значения в dict являются уникальными:

    dict((v, k) for k, v in my_map.iteritems())
    
    ответ дан sykora, с репутацией 56916, 27.01.2009
  • 107 рейтинг

    Если значения в my_map не являются уникальными:

    inv_map = {}
    for k, v in my_map.iteritems():
        inv_map[v] = inv_map.get(v, [])
        inv_map[v].append(k)
    
    ответ дан Robert Rossney, с репутацией 69975, 27.01.2009
  • 33 рейтинг
    def inverse_mapping(f):
        return f.__class__(map(reversed, f.items()))
    
    ответ дан fs., с репутацией 598, 5.11.2009
  • 28 рейтинг

    Попробуйте это:

    inv_map = dict(zip(my_map.values(), my_map.keys()))
    

    (Обратите внимание, что документы Python по представлениям словаря явно гарантируют, что элементы .keys() и .values() имеют свои элементы в одном и том же порядке, что позволяет вышеуказанному подходу работать. )

    в качестве альтернативы:

    inv_map = dict((my_map[k], k) for k in my_map)
    

    или использование Python 3. Диктовое понимание 0's

    inv_map = {my_map[k] : k for k in my_map}
    
    ответ дан sykora, с репутацией 56916, 27.01.2009
  • 17 рейтинг

    Другой, более функциональный способ:

    my_map = { 'a': 1, 'b':2 }
    dict(map(reversed, my_map.items()))
    
    ответ дан Brendan Maguire, с репутацией 1574, 26.02.2014
  • 6 рейтинг

    Это расширяет ответ Python перевернуть / инвертировать отображение , применяя к которому, когда значения в dict не являются уникальными.

    class ReversibleDict(dict):
    
        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.iteritems():
                revdict.setdefault(v, []).append(k)
            return revdict
    

    Реализация ограничена тем, что вы не можете использовать reversed дважды и получить оригинал обратно. Это не симметрично как таковое. Протестировано с Python 2. 6. Здесь - это пример использования того, как я использую для печати результирующий дикт.

    Если вы предпочитаете использовать set вместо list, и есть приложения, для которых это имеет смысл, вместо setdefault(v, []).append(k), используйте setdefault(v, set()).add(k).

    ответ дан A-B-B, с репутацией 20353, 24.10.2012
  • 5 рейтинг

    Добавление моих 2 центов питонического пути:

    inv_map = dict(map(reversed, my_map.items()))
    

    Пример:

    In [7]: my_map
    Out[7]: {1: 'one', 2: 'two', 3: 'three'}
    
    In [8]: inv_map = dict(map(reversed, my_map.items()))
    
    In [9]: inv_map
    Out[9]: {'one': 1, 'three': 3, 'two': 2}
    
    ответ дан Amit Kushwaha, с репутацией 921, 3.04.2017
  • 4 рейтинг

    Мы также можем обратить словарь с дубликатами ключей, используя defaultdict:

    from collections import Counter, defaultdict
    
    def invert_dict(d):
        d_inv = defaultdict(list)
        for k, v in c.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']}  
    

    См. здесь :

    Этот метод проще и быстрее, чем эквивалентный метод с использованием dict.setdefault().

    ответ дан irudyak, с репутацией 742, 26.12.2016
  • 4 рейтинг

    Если значения не являются уникальными, и вы немного хардкор:

    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())
    )
    

    Специально для большого слова, обратите внимание, что это решение гораздо менее эффективно, чем ответ Python перевернуть / инвертировать отображение , потому что оно повторяется items() несколько раз.

    ответ дан pcv, с репутацией 1364, 17.04.2010
  • 4 рейтинг

    Сочетание понимания списка и словаря. Можно обрабатывать дубликаты ключей

    {v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}
    
    ответ дан SVJ, с репутацией 41, 19.04.2018
  • 3 рейтинг

    В дополнение к другим функциям, предложенным выше, если вам нравятся лямбды:

    invert = lambda mydict: {v:k for k, v in mydict.items()}
    

    Или вы тоже можете сделать это так:

    invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) )
    
    ответ дан RussellStewart, с репутацией 3665, 9.04.2013
  • 3 рейтинг

    Это обрабатывает неуникальные значения и сохраняет большую часть внешнего вида уникального случая.

    inv_map = {v:[k for k in my_map if my_map[k] == v] for v in my_map.itervalues()}
    

    Для Python 3. x, замените значения на значения . Я не могу взять кредит на это. , , это было предложено Иконой Джек.

    ответ дан user1495, с репутацией 41, 25.01.2017
  • 2 рейтинг

    Использование почтового индекса

    inv_map = dict(zip(my_map.values(), my_map.keys()))
    
    ответ дан Kwaw Annor, с репутацией 926, 11.09.2016
  • 2 рейтинг

    Я думаю, что лучший способ сделать это - определить класс. Вот реализация «симметричного словаря»:

    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
    

    Методы удаления и итерации достаточно просты для реализации, если они необходимы.

    Эта реализация намного эффективнее, чем инвертирование всего словаря (который, кажется, является самым популярным решением на этой странице). Не говоря уже о том, что вы можете добавлять или удалять значения из вашего SymDict столько раз, сколько захотите, и ваш обратный словарь всегда останется действительным - это не так, если вы просто полностью измените словарь один раз.

    ответ дан NcAdams, с репутацией 755, 28.09.2014
  • 1 рейтинг
    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})
    

    Это обеспечит вывод в виде: {1: ['a', 'd'], 2: ['b'], 3: ['c']}

    ответ дан RVR, с репутацией 152, 30.08.2017
  • 1 рейтинг
      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
    

    этот код сделать так:

    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']}
    
    ответ дан Shb8086, с репутацией 11, 18.12.2017
  • 1 рейтинг

    Я бы сделал это таким образом в Python 2.

    inv_map = {my_map[x] : x for x in my_map}
    
    ответ дан genghiscrade, с репутацией 11, 26.04.2017
  • 1 рейтинг

    Попробуйте это для Python 2. 7/3. x

    inv_map={};
    for i in my_map:
        inv_map[my_map[i]]=i    
    print inv_map
    
    ответ дан dhvlnyk, с репутацией 77, 25.07.2014
  • 0 рейтинг

    Обратный ваш словарь:

    dict_ = {"k0":"v0", "k1":"v1", "k2":"v1"}
    inversed_dict_ = {val: key for key, val in dict_.items()}
    
    print(inversed_dict_["v1"])
    
    ответ дан Miladiouss, с репутацией 314, 7.06.2018
  • 0 рейтинг

    Функция симметрична для значений списка типов; Кортежи добавляются в списки при выполнении reverse_dict (reverse_dict (словарь))

    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
    
    ответ дан Alf, с репутацией 9, 24.09.2014
  • 0 рейтинг

    Если значения не являются уникальными И может быть хешем (одно измерение):

    for k, v in myDict.items():
        if len(v) > 1:
            for item in v:
                invDict[item] = invDict.get(item, [])
                invDict[item].append(k)
        else:
            invDict[v] = invDict.get(v, [])
            invDict[v].append(k)
    

    И с рекурсией, если вам нужно копать глубже, то только одно измерение:

    def digList(lst):
        temp = []
        for item in lst:
            if type(item) is list:
                temp.append(digList(item))
            else:
                temp.append(item)
        return set(temp)
    
    for k, v in myDict.items():
        if type(v) is list:
            items = digList(v)
            for item in items:
                invDict[item] = invDict.get(item, [])
                invDict[item].append(k)
        else:
            invDict[v] = invDict.get(v, [])
            invDict[v].append(k)
    
    ответ дан mveith, с репутацией 1, 10.01.2017
  • 0 рейтинг

    Поскольку словарям требуется один уникальный ключ в словаре в отличие от значений, мы должны добавить обратные значения в список сортировки, который будет включен в новые конкретные ключи.

    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
    
    ответ дан EyoelD, с репутацией 379, 9.01.2016
  • 0 рейтинг

    Не что-то совершенно другое, просто немного переписанный рецепт из Поваренной книги. Более того, он оптимизирован путем сохранения метода setdefault вместо того, чтобы каждый раз проходить его через экземпляр:

    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)
    

    Предназначен для работы под CPython 3. х, за 2. х заменить mapping.items() на mapping.iteritems()

    На моей машине работает немного быстрее, чем на других примерах здесь

    ответ дан thodnev, с репутацией 910, 2.08.2016
  • -1 рейтинг

    Быстрое функциональное решение для небиективных карт (значения не уникальны):

    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
            )
        }
    

    Теоретически это должно быть быстрее, чем добавление к набору (или добавление к списку) по одному, как в императивном решении .

    К сожалению, значения должны быть сортируемыми, сортировка требуется по группам.

    ответ дан cjay, с репутацией 15, 6.03.2014
  • -1 рейтинг

    Я написал это с помощью цикла 'for' и method '. get () 'и я изменил название «map» в словаре на «map1», потому что «map» - это функция.

    def dict_invert(map1):
        inv_map = {} # new dictionary
        for key in map1.keys():
            inv_map[map1.get(key)] = key
        return inv_map
    
    ответ дан Taras Voitovych, с репутацией 9, 5.08.2016
  • -3 рейтинг

    Это не лучшее решение, но оно работает. Скажем, словарь, который мы хотим изменить, это:

    словарь = {'a': 1, 'b': 2, 'c': 3}, затем:

    dictionary = {'a': 1, 'b': 2, 'c': 3}
    reverse_dictionary = {}
    for index, val in enumerate(list(dictionary.values())):
        reverse_dictionary[val] = list(dictionary.keys())[index]
    

    Выходные данные reverse_dictionary должны быть {1: 'a', 2: 'b', 3: 'c'}

    ответ дан user9918114, с репутацией 1, 9.06.2018
  • -3 рейтинг

    Для всех видов словарей, независимо от того, имеют ли они уникальные значения для использования в качестве ключей, вы можете создать список ключей для каждого значения

    inv_map = {v: inv_map.get(v, []) + [k] for k,v in my_map.items()}
    
    ответ дан beco, с репутацией 11, 1.11.2010
  • -5 рейтинг

    , если элементы не уникальны, попробуйте это:

         dict={}
         dict1={}
         num=int(raw_input(" how many numbers in dict?--> "))
         for i in range (0,num):
             key=raw_input(" enter key --> ")
             value=raw_input("enter value --> ")
             dict[key]=value
         keys=dict.keys()
         values=dict.values()
         for b in range (0,num):
             keys[b],values[b]=values[b],keys[b]
             dict1[keys[b]]=values[b]
         print keys
         print values
         print dict1
    
    ответ дан seiferas, с репутацией 1, 24.11.2015