Приведенный словарь выглядит так:
my_map = {'a': 1, 'b': 2}
Как можно инвертировать эту карту, чтобы получить:
inv_map = {1: 'a', 2: 'b'}
Приведенный словарь выглядит так:
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)
или с использованием python 3.0 dict
inv_map = {my_map[k] : k for k in my_map}
Другой, более функциональный способ:
my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))
Это распространяется на ответ Роберта, применимый к случаям, когда значения в 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)
.
Мы также можем изменить словарь с дубликатами ключей, используя 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()
.
Добавление моих двухцентов питонического пути:
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}
Сочетание списка и словаря. Может обрабатывать дубликаты ключей
{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}
Если значения не уникальны, а вы немного хардкор:
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())
)
Специально для большого dict, обратите внимание, что это решение намного менее эффективно, чем ответ Python обратный/инвертированный сопоставление, потому что он несколько раз повторяется items()
.
Использование zip
inv_map = dict(zip(my_map.values(), my_map.keys()))
В дополнение к другим функциям, предложенным выше, если вам нравится lambdas:
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 = {v:[k for k in my_map if my_map[k] == v] for v in my_map.itervalues()}
Для Python 3.x замените itervalues
на values
.
Например, у вас есть следующий словарь:
dict = {'a': 'fire', 'b': 'ice', 'c': 'fire', 'd': 'water'}
И вы хотите получить это в такой перевернутой форме:
inverted_dict = {'fire': ['a', 'c'], 'ice': ['b'], 'water': ['d']}
Первое решение Для инвертирования пар ключ-значение в вашем словаре используйте подход for
-loop:
# 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]}
Попробуйте это для python 2.7/3.x
inv_map={};
for i in my_map:
inv_map[my_map[i]]=i
print inv_map
Функция симметрична для значений списка типов; Кортежи прикрываются списками при выполнении 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
Быстрое функциональное решение для небиективных отображений (значения не единственные):
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.
Я бы сделал это в 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']}
Обратный ваш словарь:
dict_ = {"k0":"v0", "k1":"v1", "k2":"v1"}
inversed_dict_ = {val: key for key, val in dict_.items()}
print(inversed_dict_["v1"])
Согласно моему комментарию к вопросу. Я думаю, что самый простой и один вкладыш, который работает как для Python2, так и для Python 3, будет
dict(zip(inv_map.values(), inv_map.keys()))
Не совсем другое, просто переписан рецепт из Cookbook. Он более оптимизирован, сохраняя метод 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" и метода ".get()", и я изменил имя "карта" словаря на "map1", потому что "map" - это функция.
def dict_invert(map1):
inv_map = {} # new dictionary
for key in map1.keys():
inv_map[map1.get(key)] = key
return inv_map
Если значения не уникальны И может быть хешем (одно измерение):
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)
Для всех видов словаря, независимо от того, не имеют ли они уникальных значений для использования в качестве ключей, вы можете создать список ключей для каждого значения
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'}