Вопрос

Учитывая такой словарь:

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

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

inv_map = { 1: 'a', 2: 'b' }
Это было полезно?

Решение

Для 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()}

Другие советы

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

dict((v, k) for k, v in my_map.iteritems())

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

inv_map = {}
for k, v in my_map.iteritems():
    inv_map[v] = inv_map.get(v, [])
    inv_map[v].append(k)

Чтобы сделать это, сохраняя тип вашего сопоставления (при условии, что это dict или dict подкласс):

def inverse_mapping(f):
    return f.__class__(map(reversed, f.items()))

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

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)

или используя понимание dict Python 3.0

inv_map = {my_map[k] : k for k in my_map}

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

my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))

Это расширяет ответ https://stackoverflow.com/questions/483666/python-reverse-inverse-a-mapping/485368#485368, применяется к случаям, когда значения в словаре не уникальны.

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

Мы также можем перевернуть словарь с повторяющимися ключами, используя 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().

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

{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}

Добавляю свои 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}

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

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() много раз.

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

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

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

invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) )

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

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 столько, сколько захотите, и ваш инверсный словарь всегда останется действительным - это не так, если вы просто один раз перевернете весь словарь.

С использованием молния

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

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

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

Для Python 3.x замените итеративные значения с ценности.Я не могу поставить себе в этом заслугу...это было предложено Icon Jack.

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

inv_map={};
for i in my_map:
    inv_map[my_map[i]]=i    
print inv_map

Например, у вас есть следующий словарь:

dict = {'a': 'fire', 'b': 'ice', 'c': 'fire', 'd': 'water'}

И вы хотите получить это в такой перевернутой форме:

inverted_dict = {'fire': ['a', 'c'], 'ice': ['b'], 'water': ['d']}

Первое решение.Для инвертирования ключ-значение пары в вашем словаре используйте for-циклический подход:

# Use this code to invert dictionaries that have non-unique values

inverted_dict = dictio()
for key, value in dict.items():
    inverted_dict.setdefault(value, list()).append(key)

Второе решение.Использовать понимание словаря подход к инверсии:

# Use this code to invert dictionaries that have unique values

inverted_dict = {value: key for key, value in dict.items()}

Третье решение.Использовать возвращение инверсии подход:

# Use this code to invert dictionaries that have lists of values

dict = {value: key for key in inverted_dict for value in my_map[key]}

Функция симметрична для значений типа list;Кортежи преобразуются в списки при выполненииverse_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

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

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

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

inv_map = {my_map[x] : x for x in my_map}
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:['а', 'д'], 2:['б'], 3:['с']}

  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']}

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

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

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

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

Не что-то совсем другое, просто немного переписанный рецепт из Поваренной книги.Кроме того, он оптимизирован за счет сохранения 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.x, для версии 2.x замените mapping.items() с mapping.iteritems()

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

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

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)

Инвертируйте словарь:

dict_ = {"k0":"v0", "k1":"v1", "k2":"v1"}
inversed_dict_ = {val: key for key, val in dict_.items()}

print(inversed_dict_["v1"])

Я написал это с помощью цикла for и метода .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

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

inv_map = {v: inv_map.get(v, []) + [k] for k,v in my_map.items()}

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

словарь = {'а':1, 'б':2, 'в':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]

Выходные данныеverse_dictionary должны быть {1:'а', 2:'б', 3:'с'}

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top