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



данный словарь, как так:



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


как можно инвертировать эту карту сделать:



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


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

968   29  

29 ответов:

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

или с помощью диктантов 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()))

это расширяет ответ Python reverse / invert a mapping, применяя в случаях, когда значения в словаре, не являются уникальными.

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 чем a list и есть приложения, для которых это имеет смысл, а не setdefault(v, []).append(k) используйте setdefault(v, set()).add(k).

добавить мои 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 reverse / invert a mapping потому что он перебирает items() несколько раз.

мы также можем отменить словарь с дубликатами ключей с помощью 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()}

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

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

или, вы могли бы сделать это таким образом:

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

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

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

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

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

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

С помощью zip

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

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

inv_map={};
for i in my_map:
    inv_map[my_map[i]]=i    
print inv_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: ['a', 'd'], 2: ['b'], 3: ['c']}

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

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

не что-то совершенно другое, просто немного переписать рецепт из Поваренной книги. Кроме того, он оптимизирован путем сохранения 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"])

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

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

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

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

Я написал это с помощью цикла ' for 'и метода'.получить () и я изменил название "Карта" словарь 'карта1, потому что "карта" - это функция.

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

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

dictionary = {'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'}

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

     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

Comments

    Ничего не найдено.