Gegeven een woordenboek als volgt:
my_map = {'a': 1, 'b': 2}
Hoe kan men deze kaart omkeren om het volgende te krijgen:
inv_map = {1: 'a', 2: 'b'}
Antwoord 1, autoriteit 100%
Python 3+:
inv_map = {v: k for k, v in my_map.items()}
Python 2:
inv_map = {v: k for k, v in my_map.iteritems()}
Antwoord 2, autoriteit 16%
Ervan uitgaande dat de waarden in het dictaat uniek zijn:
dict((v, k) for k, v in my_map.iteritems())
Antwoord 3, autoriteit 13%
Als de waarden in my_map
niet uniek zijn:
inv_map = {}
for k, v in my_map.iteritems():
inv_map[v] = inv_map.get(v, []) + [k]
Antwoord 4, autoriteit 4%
Om dit te doen met behoud van het type toewijzing (ervan uitgaande dat het een dict
of een dict
subklasse is):
def inverse_mapping(f):
return f.__class__(map(reversed, f.items()))
Antwoord 5, autoriteit 4%
Probeer dit:
inv_map = dict(zip(my_map.values(), my_map.keys()))
(Merk op dat de Python-documenten over woordenboekweergavenexpliciet garandeer dat .keys()
en .values()
hun elementen in dezelfde volgorde hebben, waardoor de bovenstaande aanpak werkt.)
Alternatief:
inv_map = dict((my_map[k], k) for k in my_map)
of het gebruik van de dicteerbegrippen van python 3.0
inv_map = {my_map[k] : k for k in my_map}
Antwoord 6, autoriteit 3%
Een andere, meer functionele manier:
my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))
7
Dit breidt uit bij het antwoord door Robert , solliciteren op wanneer de waarden in de dict niet uniek zijn.
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
De implementatie is beperkt doordat u niet reversed
kunt gebruiken en de originele rug krijgt. Het is niet symmetrisch als zodanig. Het is getest met Python 2.6. hier is een gebruik van hoe ik gebruik om het resulterende dict af te drukken.
Als u liever een set
gebruiken dan een list
, en er kunnen ongeordende toepassingen bestaan waarvoor dit logisch is, in plaats van setdefault(v, []).append(k)
, gebruik setdefault(v, set()).add(k)
toe.
8
We kunnen ook een woordenboek met dubbele toetsen omkeren met defaultdict
:
from collections import Counter, defaultdict
def invert_dict(d):
d_inv = defaultdict(list)
for k, v in d.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']}
Zie hier:
Deze techniek is eenvoudiger en sneller dan een equivalente techniek die
dict.setdefault()
gebruikt.
Antwoord 9
Combinatie van lijst- en woordenboekbegrip. Kan dubbele sleutels aan
{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}
Antwoord 10
Je hebt bijvoorbeeld het volgende woordenboek:
dict = {'a': 'fire', 'b': 'ice', 'c': 'fire', 'd': 'water'}
En je wilt het in zo’n omgekeerde vorm krijgen:
inverted_dict = {'fire': ['a', 'c'], 'ice': ['b'], 'water': ['d']}
Eerste oplossing. Gebruik voor het omkeren van sleutel-waarde-paren in uw woordenboek een for
-loop-aanpak:
# Use this code to invert dictionaries that have non-unique values
inverted_dict = dict()
for key, value in dict.items():
inverted_dict.setdefault(value, list()).append(key)
Tweede oplossing. Gebruik een woordenboekbegrip-aanpak voor inversie:
# Use this code to invert dictionaries that have unique values
inverted_dict = {value: key for key, value in dict.items()}
Derde oplossing. Gebruik het terugdraaien van de inversie-benadering (vertrouwt op de tweede oplossing):
# 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]}
Antwoord 11
Ik denk dat de beste manier om dit te doen is door een klasse te definiëren. Hier is een implementatie van een “symmetrisch woordenboek”:
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
Verwijder- en iteratiemethoden zijn eenvoudig genoeg om te implementeren als ze nodig zijn.
Deze implementatie is veel efficiënter dan het omkeren van een heel woordenboek (wat de meest populaire oplossing op deze pagina lijkt te zijn). Om nog maar te zwijgen van het feit dat u zoveel waarden aan uw SymDict kunt toevoegen of verwijderen als u wilt, en uw inverse-woordenboek blijft altijd geldig – dit is niet waar als u het hele woordenboek één keer omdraait.
Antwoord 12
Als de waarden niet uniek zijn en je een beetje hardcore bent:
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())
)
Vooral voor een groot dictaat, houd er rekening mee dat deze oplossing veel minder efficiënt is dan het antwoord Python keert een toewijzing om / inverteert dezeomdat deze meerdere keren over items()
heen gaat.
Antwoord 13
Dit verwerkt niet-unieke waarden en behoudt veel van het uiterlijk van de unieke case.
inv_map = {v:[k for k in my_map if my_map[k] == v] for v in my_map.itervalues()}
Voor Python 3.x vervangt u itervalues
door values
.
Antwoord 14
Ik ontdekte dat deze versie meer dan 10% sneller is dan de geaccepteerde versie van een woordenboek met 10.000 sleutels.
d = {i: str(i) for i in range(10000)}
new_d = dict(zip(d.values(), d.keys()))
Antwoord 15
Een geval waarin de woordenboekwaarden een set zijn. Vind ik leuk:
some_dict = {"1":{"a","b","c"},
"2":{"d","e","f"},
"3":{"g","h","i"}}
Het omgekeerde zou willen:
some_dict = {vi: k for k, v in some_dict.items() for vi in v}
De uitvoer is als volgt:
{'c': '1',
'b': '1',
'a': '1',
'f': '2',
'd': '2',
'e': '2',
'g': '3',
'h': '3',
'i': '3'}
Antwoord 16
In aanvulling op de andere hierboven voorgestelde functies, als je van lambda’s houdt:
invert = lambda mydict: {v:k for k, v in mydict.items()}
Of je zou het ook op deze manier kunnen doen:
invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) )
Antwoord 17
Hier is een andere manier om het te doen.
my_map = {'a': 1, 'b': 2}
inv_map= {}
for key in my_map.keys() :
val = my_map[key]
inv_map[val] = key
Antwoord 18
Ik ben me ervan bewust dat deze vraag al veel goede antwoorden heeft, maar ik wilde deze zeer nette oplossing delen die ook zorgt voor dubbele waarden:
def dict_reverser(d):
seen = set()
return {v: k for k, v in d.items() if v not in seen or seen.add(v)}
Dit is afhankelijk van het feit dat set.add
altijd None
retourneert in Python.
Antwoord 19
Veel antwoorden, maar niets duidelijks gevonden voor het geval we het hebben over een woordenboek met niet-unieke waarden.
Een oplossing zou zijn:
from collections import defaultdict
inv_map = defaultdict(list)
for k, v in my_map.items():
inv_map[v].append(k)
Voorbeeld:
If initiële dict my_map = {'c': 1, 'd': 5, 'a': 5, 'b': 10}
dan geeft het uitvoeren van de bovenstaande code het volgende:
{5: ['a', 'd'], 1: ['c'], 10: ['b']}
Antwoord 20
Functie is symmetrisch voor waarden van het type lijst; Tupels worden omgezet in lijsten bij het uitvoeren van 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
Antwoord 21
Aangezien woordenboeken één unieke sleutel in het woordenboek vereisen, in tegenstelling tot waarden, moeten we de omgekeerde waarden toevoegen aan een lijst met sorteringen die moeten worden opgenomen in de nieuwe specifieke sleutels.
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
Antwoord 22
Snelle functionele oplossing voor niet-bijjectieve kaarten (waarden niet uniek):
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
)
}
In theorie zou dit sneller moeten zijn dan één voor één toevoegen aan de set (of toevoegen aan de lijst), zoals in de noodzakelijke oplossing.
Helaas moeten de waarden sorteerbaar zijn, de sortering is vereist per groupby.
Antwoord 23
Probeer dit voor python 2.7/3.x
inv_map={};
for i in my_map:
inv_map[my_map[i]]=i
print inv_map
Antwoord 24
Een lambda-oplossing voor de huidige python 3.x-versies:
d1 = dict(alice='apples', bob='bananas')
d2 = dict(map(lambda key: (d1[key], key), d1.keys()))
print(d2)
Resultaat:
{'apples': 'alice', 'bananas': 'bob'}
Deze oplossing controleert niet op duplicaten.
Enkele opmerkingen:
- Het lambda-construct heeft toegang tot d1 vanuit de buitenste scope, dus we hebben alleen
de huidige sleutel doorgeven. Het geeft een tuple terug. - De dict() constructor accepteert een lijst met tuples. Het
accepteert ook het resultaat van een kaart, dus we kunnen de conversie overslaan naar a
lijst. - Deze oplossing heeft geen expliciete
for
-lus. Het vermijdt ook het gebruik van eenlist comprehension
voor degenen die slecht zijn in wiskunde 😉
Antwoord 25
Ik zou het zo doen in python 2.
inv_map = {my_map[x] : x for x in my_map}
Antwoord 26
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})
Hiermee leveren u uitvoer als: {1: [‘A’, ‘D’], 2: [‘B’], 3: [‘C’]}
27
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
Deze code vindt dit leuk:
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']}
Antwoord 28
Ik heb dit geschreven met behulp van cyclus ‘for’ en methode ‘.get()’ en ik heb de naam ‘map’ van het woordenboek gewijzigd in ‘map1’ omdat ‘map’ een functie is.
def dict_invert(map1):
inv_map = {} # new dictionary
for key in map1.keys():
inv_map[map1.get(key)] = key
return inv_map
Antwoord 29
Als waarden niet uniek zijn EN mogelijk een hash zijn (één dimensie):
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)
En met een recursie als je dieper moet graven dan slechts één dimensie:
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)