Python reverse / инвертировать отображение
данный словарь, как так:
my_map = { 'a': 1, 'b':2 }
как можно инвертировать эту карту сделать:
inv_map = { 1: 'a', 2: 'b' }
ПРИМЕЧАНИЕ:map изменено на my_map чтобы избежать конфликтов со встроенной функцией,map. Некоторые комментарии могут быть затронуты ниже.
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()}
Если значения в
my_mapне уникальны:inv_map = {} for k, v in my_map.iteritems(): inv_map[v] = inv_map.get(v, []) inv_map[v].append(k)
попробуйте это:
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}
это расширяет ответ 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чем alistи есть приложения, для которых это имеет смысл, а не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()))
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