Een woordenboektoewijzing omkeren / omkeren

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_mapniet 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 dictof een dictsubklasse 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 reversedkunt 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 setgebruiken 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 itervaluesdoor 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.addaltijd Noneretourneert 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 een list comprehensionvoor 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)

Other episodes