Wie tausche ich Schlüssel mit Werten in einem Wörterbuch aus?

96

Ich erhalte ein Wörterbuch als Eingabe und möchte ein Wörterbuch zurückgeben, dessen Schlüssel die Werte der Eingabe und dessen Wert die entsprechenden Eingabeschlüssel sind. Werte sind einzigartig.

Angenommen, meine Eingabe lautet:

a = dict()
a['one']=1
a['two']=2

Ich möchte, dass meine Ausgabe ist:

{1: 'one', 2: 'two'}

Zur Verdeutlichung möchte ich, dass mein Ergebnis dem folgenden entspricht:

res = dict()
res[1] = 'one'
res[2] = 'two'

Gibt es einen ordentlichen pythonischen Weg, um dies zu erreichen?

Roee Adler
quelle
1
Unter stackoverflow.com/questions/1087694/… finden Sie eine identische Frage, die eine gute Antwort bietet, wenn Sie Python 3
Stephen Edmonds verwenden.
@Stephen: Siehe die am zweithäufigsten gewählte Antwort. Sie entspricht der akzeptierten Antwort in der Frage, mit der Sie verlinkt haben. Die Menge bevorzugte jedoch die andere Antwort ...
Roee Adler
4
Python ist kein Perl, Python ist kein Rubin. Lesbarkeit zählt. Spärlich ist besser als dicht. Angesichts dessen sind alle Methoden dieser Antworten nur schlecht ™; Der in der Frage ist der beste Weg.
o0 '.
3
Mögliches Duplikat von Python Reverse / Inverse eines Mappings
Cory

Antworten:

147

Python 2:

res = dict((v,k) for k,v in a.iteritems())

Python 3 (danke an @erik):

res = dict((v,k) for k,v in a.items())
liori
quelle
14
Dies scheint zwar richtig zu sein, aber es ist wirklich gut, eine Erklärung hinzuzufügen, wie es funktioniert, und nicht nur den Code.
Wird
4
Was ist, wenn Werte nicht eindeutig sind? Dann sollten die Schlüssel eine Liste sein ... zum Beispiel: d = {'a': 3, 'b': 2, 'c': 2} {v: k für k, v in d.iteritems ()} { 2: 'b', 3: 'a'} sollte {2: ['b', 'c'], 3: 'a'} sein
Hanan Shteingart
4
@ HananShteingart: Die in der Frage des OP angegebenen Werte sind eindeutig. Bitte erstellen Sie einen separaten Fragenbeitrag für Ihren Fall (und verlinken Sie ihn vorzugsweise hier für andere Personen).
Liori
Der Python2-Code funktioniert ... aber dem Listenverständnis fehlt das [und ]. Benötigt ein Listenverständnis nicht das [und ]?
Trevor Boyd Smith
@TrevorBoydSmith: Dies ist kein Listenverständnis, dies ist ein Generatorausdruck .
Liori
55
new_dict = dict(zip(my_dict.values(), my_dict.keys()))
Javier
quelle
4
Haben wirklich Werte () und Schlüssel () garantiert die gleiche Reihenfolge?
Lennart Regebro
1
Ja, von python.org/dev/peps/pep-3106 Die Spezifikation impliziert, dass die Reihenfolge, in der Elemente von .keys (), .values ​​() und .items () zurückgegeben werden, dieselbe ist (genau wie in Python) 2.x), da die Reihenfolge alle vom Diktator abgeleitet ist (der vermutlich willkürlich, aber stabil ist, solange ein Diktat nicht geändert wird). Diese Antwort muss jedoch zweimal my_dict aufrufen (eine für Werte, eine für Schlüssel). Vielleicht ist das nicht ideal.
Sunqiang
4
Ja, diese Antwort durchläuft das Diktat zweimal. Die Antwort von sunqiang ist für ein großes Wörterbuch vorzuziehen, da nur eine Iteration erforderlich ist.
Carl Meyer
@ Carl Meyer: stimme zu, er verwendet auch itertools, die für große Datenmengen viel besser sind. obwohl ich mich frage, ob der letzte dict () -Aufruf auch gestreamt wird oder ob er zuerst die gesamte Paarliste zusammenstellt
Javier
@CarlMeyer zusätzlich für n> 1e6 (oder 1e9) wird die Speichernutzung auch sehr groß sein ... und dies auch ein paar verlangsamen.
Trevor Boyd Smith
47

Ab Python 2.7, einschließlich 3.0+, gibt es eine wohl kürzere, besser lesbare Version:

>>> my_dict = {'x':1, 'y':2, 'z':3}
>>> {v: k for k, v in my_dict.items()}
{1: 'x', 2: 'y', 3: 'z'}
SilentGhost
quelle
30
In [1]: my_dict = {'x':1, 'y':2, 'z':3}

In [2]: dict((value, key) for key, value in my_dict.iteritems())
Out[2]: {1: 'x', 2: 'y', 3: 'z'}
Sunqiang
quelle
3
Nicht in der ursprünglichen Frage, ich bin nur neugierig, was passieren wird, wenn Sie doppelte Werte im ursprünglichen Wörterbuch hatten und dann Schlüssel / Werte mit dieser Methode austauschen?
Andre Miller
2
@Andre Miller: Es dauert das letzte Auftreten des bestimmten Schlüssels: dict (((1,3), (1,2))) == {1: 2}
balpha
2
Duplikate werden mit dem zuletzt aufgetretenen Duplikat überschrieben.
Christopher
2
@Andre Miller: Und weil d.items () Elemente in einer beliebigen Reihenfolge zurückgibt, erhalten Sie einen beliebigen Schlüssel für doppelte Werte.
Ants Aasma
Ich denke, dass es das letzte Schlüssel-Wert-Paar braucht, das es gefunden hat. Es ist wie ein ['x'] = 3. Dann setzen Sie ein ['x'] = 4.
Riza
28

Sie können das Diktatverständnis nutzen :

res = {v: k for k, v in a.iteritems()}

Bearbeitet: Verwenden Sie für Python 3 a.items()anstelle von a.iteritems(). Diskussionen über die Unterschiede zwischen ihnen finden Sie in Iteritems in Python on SO.

Akavall
quelle
18

Du könntest es versuchen:

d={'one':1,'two':2}
d2=dict((value,key) for key,value in d.iteritems())
d2
  {'two': 2, 'one': 1}

Beachten Sie, dass Sie ein Wörterbuch nicht "umkehren" können, wenn

  1. Mehr als ein Schlüssel hat denselben Wert. Zum Beispiel {'one':1,'two':1}. Das neue Wörterbuch kann nur ein Element mit Schlüssel enthalten 1.
  2. Einer oder mehrere der Werte sind nicht verwertbar. Zum Beispiel {'one':[1]}. [1]ist ein gültiger Wert, aber kein gültiger Schlüssel.

In diesem Thread auf der Python-Mailingliste finden Sie eine Diskussion zu diesem Thema.

Alasdair
quelle
Auch +1 über den Hinweis, dass die Werte im ursprünglichen Diktat eindeutig sind; Andernfalls werden Sie im "umgekehrten" Diktat überschrieben ... und dies (ich habe es gerade auf meine Kosten gefunden) kann zu kniffligen Fehlern in Ihrem Code führen!
Monojohnny
15

Die aktuell führende Antwort geht davon aus, dass die Werte eindeutig sind, was nicht immer der Fall ist. Was ist, wenn Werte nicht eindeutig sind? Sie verlieren Informationen! Beispielsweise:

d = {'a':3, 'b': 2, 'c': 2} 
{v:k for k,v in d.iteritems()} 

kehrt zurück {2: 'b', 3: 'a'}.

Die Informationen über 'c'wurden vollständig ignoriert. Idealerweise sollte es so etwas sein {2: ['b','c'], 3: ['a']}. Dies ist, was die unterste Implementierung tut.

Python 2.x.

def reverse_non_unique_mapping(d):
    dinv = {}
    for k, v in d.iteritems():
        if v in dinv:
            dinv[v].append(k)
        else:
            dinv[v] = [k]
    return dinv

Python 3.x.

def reverse_non_unique_mapping(d):
    dinv = {}
    for k, v in d.items():
        if v in dinv:
            dinv[v].append(k)
        else:
            dinv[v] = [k]
    return dinv
Hanan Shteingart
quelle
Dies sollte die richtige Antwort sein, da es sich um einen allgemeineren Fall handelt
Leon Rai
Danke dafür! Ich habe Informationen mit den anderen Lösungen verloren.
Cam
14

res = dict(zip(a.values(), a.keys()))

pkit
quelle
4
dict garantiert nicht, dass seine Werte () und Schlüssel () Elemente in derselben Reihenfolge zurückgeben. Außerdem geben keys (), values ​​() und zip () eine Liste zurück, in der ein Iterator ausreichend wäre.
Liori
19
@liori: Du liegst falsch. dict garantiert, dass die Werte () und keys () in derselben Reihenfolge liegen, wenn Sie das dict zwischen den Aufrufen von values ​​() und keys () natürlich nicht ändern. In der Dokumentation heißt es hier: (Lesen Sie den Teil "Hinweis": docs.python.org/library/stdtypes.html#dict.items ) "If items (), keys (), values ​​(), iteritems (), iterkeys ( ) und itervalues ​​() werden ohne dazwischenliegende Änderungen am Wörterbuch aufgerufen, die Listen entsprechen direkt. "
Nosklo
1
Ok, dann irre ich mich ... Ich habe die Online-Dokumente nicht überprüft. Vielen Dank für den Hinweis.
Liori
Sie können den Iterator itertools.izip anstelle von zip verwenden, um diese Antwort effizienter zu gestalten.
Alasdair
Und iterkeys und itervalues. Könnte aber genauso gut iteritems ()
nosklo
14
new_dict = dict( (my_dict[k], k) for k in my_dict)

oder noch besser, funktioniert aber nur in Python 3:

new_dict = { my_dict[k]: k for k in my_dict}
balpha
quelle
2
Tatsächlich funktionieren Dict Comprehensions ( PEP 274 ) auch mit Python 2.7.
Arseny
10

Eine andere Möglichkeit, die Antwort von Ilya Prokin zu erweitern, besteht darin, die reversedFunktion tatsächlich zu verwenden .

dict(map(reversed, my_dict.items()))

Im Wesentlichen wird Ihr Wörterbuch durchlaufen (wobei .items()), wobei jedes Element ein Schlüssel / Wert-Paar ist, und diese Elemente werden mit der reversedFunktion ausgetauscht . Wenn dies an den dictKonstruktor übergeben wird, werden sie in Wert / Schlüssel-Paare umgewandelt, was Sie möchten.

Sonniger Patel
quelle
6

Verbesserungsvorschlag für Javier Antwort:

dict(zip(d.values(),d))

Anstatt d.keys() können Sie nur schreiben d, denn wenn Sie das Wörterbuch mit einem Iterator durchgehen, werden die Schlüssel des entsprechenden Wörterbuchs zurückgegeben.

Ex. für dieses Verhalten:

d = {'a':1,'b':2}
for k in d:
 k
'a'
'b'
shadow2097
quelle
3

Kann leicht mit Wörterbuchverständnis gemacht werden:

{d[i]:i for i in d}
user10084443
quelle
2
dict(map(lambda x: x[::-1], YourDict.items()))

.items()gibt eine Liste von Tupeln von zurück (key, value). map()Durchläuft Elemente der Liste und wendet sie lambda x:[::-1]auf jedes Element (Tupel) an, um sie umzukehren, sodass jedes Tupel (value, key)in die neue Liste aufgenommen wird, die aus der Karte herausgespuckt wurde. Schließlich dict()macht ein Diktat aus der neuen Liste.

Ilya Prokin
quelle
.items () gibt eine Liste von Tupeln (Schlüssel, Wert) zurück. map () geht Elemente der Liste durch und wendet sie lambda x:[::-1]auf jedes ihrer Elemente (Tupel) an, um sie umzukehren, sodass jedes Tupel (Wert, Schlüssel) in der neuen Liste wird, die aus der Karte ausgespuckt wird. Schließlich macht dict () ein Diktat aus der neuen Liste.
Ilya Prokin
1

Verwenden der Schleife : -

newdict = {} #Will contain reversed key:value pairs.

for key, value in zip(my_dict.keys(), my_dict.values()):
    # Operations on key/value can also be performed.
    newdict[value] = key
Devesh Saini
quelle
1

Wenn Sie Python3 verwenden, ist es etwas anders:

res = dict((v,k) for k,v in a.items())
Schwerkraftgrab
quelle
1

Hinzufügen einer In-Place-Lösung:

>>> d = {1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> for k in list(d.keys()):
...     d[d.pop(k)] = k
... 
>>> d
{'two': 2, 'one': 1, 'four': 4, 'three': 3}

In Python3 ist es wichtig, dass Sie verwenden, list(d.keys())da dict.keyseine Ansicht der Schlüssel zurückgegeben wird. Wenn Sie Python2 verwenden, d.keys()ist dies ausreichend.

timgeb
quelle
1

Hanans Antwort ist die richtige, da sie einen allgemeineren Fall abdeckt (die anderen Antworten sind für jemanden, der sich der doppelten Situation nicht bewusst ist, irreführend). Eine Verbesserung von Hanans Antwort ist die Verwendung von setdefault:

mydict = {1:a, 2:a, 3:b}   
result = {}
for i in mydict:  
   result.setdefault(mydict[i],[]).append(i)
print(result)
>>> result = {a:[1,2], b:[3]}
Pegah
quelle