Konvertieren Sie zwei Listen in ein Wörterbuch

1228

Stellen Sie sich vor, Sie haben:

keys = ['name', 'age', 'food']
values = ['Monty', 42, 'spam']

Was ist der einfachste Weg, um das folgende Wörterbuch zu erstellen?

a_dict = {'name' : 'Monty', 'age' : 42, 'food' : 'spam'}
Guido
quelle

Antworten:

2143

So was:

>>> keys = ['a', 'b', 'c']
>>> values = [1, 2, 3]
>>> dictionary = dict(zip(keys, values))
>>> print(dictionary)
{'a': 1, 'b': 2, 'c': 3}

Voila :-) Der paarweise dictKonstruktor und die zipFunktion sind äußerst nützlich: https://docs.python.org/3/library/functions.html#func-dict

Dan Lenski
quelle
3
Es ist erwähnenswert, dass dictionary = {zip(keys, values)}das nicht funktioniert. Sie müssen ausdrücklich erklären alsdict(...)
Fernando Wittmann
5
Ich bin mir nicht sicher, warum du das erwarten würdest, @FernandoWittmann. {thing}ist syntaktischer Zucker, um ein set()Element zu konstruieren, das ein Element enthält. {*iterable}ist syntaktischer Zucker, um ein setElement zu konstruieren, das mehrere Elemente enthält. {k:v}oder {**mapping} wird ein konstruieren dict, aber das ist syntaktisch ziemlich verschieden.
Dan Lenski
6
Danke für den Kommentar Dan. Du hast recht. Meine Verwirrung geschah, weil ich normalerweise die Sintax {}für Wörterbücher verwende. In der Tat, wenn wir versuchen, ist type({})die Ausgabe dict. Aber in der Tat, wenn wir es versuchen, type({thing})dann ist die Ausgabe set.
Fernando Wittmann
Ich bin hierher gekommen, falls wir es besser machen können als {k:v for k, v in zip(keys, values)}. Es stellt sich heraus, dass wir es können. +1.
JG
139

Stellen Sie sich vor, Sie haben:

keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')

Was ist der einfachste Weg, um das folgende Wörterbuch zu erstellen?

dict = {'name' : 'Monty', 'age' : 42, 'food' : 'spam'}

Am performantesten, dictKonstruktor mitzip

new_dict = dict(zip(keys, values))

In Python 3 gibt zip jetzt einen faulen Iterator zurück, und dies ist jetzt der performanteste Ansatz.

dict(zip(keys, values))erfordert jeweils die einmalige globale Suche für dictund zip, bildet jedoch keine unnötigen Zwischendatenstrukturen oder muss sich mit lokalen Suchvorgängen in der Funktionsanwendung befassen.

Zweiter, Diktatverständnis:

Ein enger Zweitplatzierter bei der Verwendung des Diktatkonstruktors ist die Verwendung der nativen Syntax eines Diktatverständnisses (kein Listenverständnis , wie andere es fälschlicherweise ausgedrückt haben):

new_dict = {k: v for k, v in zip(keys, values)}

Wählen Sie diese Option, wenn Sie basierend auf den Schlüsseln oder dem Wert zuordnen oder filtern müssen.

Gibt in Python 2 zipeine Liste zurück, um zu vermeiden, dass eine unnötige Liste erstellt wird. Verwenden Sie izipstattdessen (Alias ​​auf Zip kann Codeänderungen reduzieren, wenn Sie zu Python 3 wechseln).

from itertools import izip as zip

Das ist also immer noch (2.7):

new_dict = {k: v for k, v in zip(keys, values)}

Python 2, ideal für <= 2.6

izipfrom itertoolswird zipin Python 3. izipist besser als zip für Python 2 (da es die unnötige Listenerstellung vermeidet) und ideal für 2.6 oder niedriger:

from itertools import izip
new_dict = dict(izip(keys, values))

Ergebnis für alle Fälle:

Auf alle Fälle:

>>> new_dict
{'age': 42, 'name': 'Monty', 'food': 'spam'}

Erläuterung:

Wenn wir uns die Hilfe dictansehen, sehen wir, dass es verschiedene Formen von Argumenten gibt:


>>> help(dict)

class dict(object)
 |  dict() -> new empty dictionary
 |  dict(mapping) -> new dictionary initialized from a mapping object's
 |      (key, value) pairs
 |  dict(iterable) -> new dictionary initialized as if via:
 |      d = {}
 |      for k, v in iterable:
 |          d[k] = v
 |  dict(**kwargs) -> new dictionary initialized with the name=value pairs
 |      in the keyword argument list.  For example:  dict(one=1, two=2)

Der optimale Ansatz besteht darin, eine Iterable zu verwenden und gleichzeitig unnötige Datenstrukturen zu vermeiden. In Python 2 erstellt zip eine unnötige Liste:

>>> zip(keys, values)
[('name', 'Monty'), ('age', 42), ('food', 'spam')]

In Python 3 wäre das Äquivalent:

>>> list(zip(keys, values))
[('name', 'Monty'), ('age', 42), ('food', 'spam')]

und Python 3 ziperstellt lediglich ein iterierbares Objekt:

>>> zip(keys, values)
<zip object at 0x7f0e2ad029c8>

Da wir vermeiden möchten, unnötige Datenstrukturen zu erstellen, möchten wir normalerweise Python 2 vermeiden zip(da dadurch eine unnötige Liste erstellt wird).

Weniger performante Alternativen:

Dies ist ein Generatorausdruck, der an den Diktatkonstruktor übergeben wird:

generator_expression = ((k, v) for k, v in zip(keys, values))
dict(generator_expression)

oder äquivalent:

dict((k, v) for k, v in zip(keys, values))

Und dies ist ein Listenverständnis, das an den Diktatkonstruktor weitergegeben wird:

dict([(k, v) for k, v in zip(keys, values)])

In den ersten beiden Fällen wird eine zusätzliche Schicht nicht operativer (daher unnötiger) Berechnungen über die iterierbare Zip-Datei gelegt, und im Fall des Listenverständnisses wird unnötigerweise eine zusätzliche Liste erstellt. Ich würde erwarten, dass alle weniger performant sind, und schon gar nicht mehr.

Leistungsbeurteilung:

In 64-Bit-Python 3.8.2 von Nix unter Ubuntu 16.04, geordnet vom schnellsten zum langsamsten:

>>> min(timeit.repeat(lambda: dict(zip(keys, values))))
0.6695233230129816
>>> min(timeit.repeat(lambda: {k: v for k, v in zip(keys, values)}))
0.6941362579818815
>>> min(timeit.repeat(lambda: {keys[i]: values[i] for i in range(len(keys))}))
0.8782548159942962
>>> 
>>> min(timeit.repeat(lambda: dict([(k, v) for k, v in zip(keys, values)])))
1.077607496001292
>>> min(timeit.repeat(lambda: dict((k, v) for k, v in zip(keys, values))))
1.1840861019445583

dict(zip(keys, values)) gewinnt auch mit kleinen Sätzen von Schlüsseln und Werten, aber bei größeren Sätzen werden die Leistungsunterschiede größer.

Ein Kommentator sagte:

minscheint ein schlechter Weg zu sein, um die Leistung zu vergleichen. Sicherlich meanund / oder maxwären viel nützlichere Indikatoren für den tatsächlichen Gebrauch.

Wir verwenden, minweil diese Algorithmen deterministisch sind. Wir wollen die Leistung der Algorithmen unter den bestmöglichen Bedingungen kennen.

Wenn das Betriebssystem aus irgendeinem Grund hängt, hat es nichts mit dem zu tun, was wir vergleichen möchten. Daher müssen wir diese Art von Ergebnissen von unserer Analyse ausschließen.

Wenn wir meandiese Art von Ereignissen verwenden , werden unsere Ergebnisse stark verzerrt, und wenn wir sie verwenden, erhalten maxwir nur das extremste Ergebnis - das wahrscheinlichste, das von einem solchen Ereignis betroffen ist.

Ein Kommentator sagt auch:

In Python 3.6.8 ist das Diktatverständnis unter Verwendung von Mittelwerten tatsächlich noch schneller, und zwar um etwa 30% für diese kleinen Listen. Bei größeren Listen (10.000 Zufallszahlen) ist der dictAnruf etwa 10% schneller.

Ich nehme an, wir meinen dict(zip(...mit 10.000 Zufallszahlen. Das klingt nach einem ziemlich ungewöhnlichen Anwendungsfall. Es ist sinnvoll, dass die direktesten Anrufe in großen Datenmengen dominieren, und ich wäre nicht überrascht, wenn die Betriebssystem-Hänge dominieren würden, wenn man bedenkt, wie lange es dauern würde, diesen Test auszuführen und Ihre Zahlen weiter zu verzerren. Und wenn Sie verwenden meanoder maxich würde Ihre Ergebnisse für bedeutungslos halten.

Verwenden wir für unsere Top-Beispiele eine realistischere Größe:

import numpy
import timeit
l1 = list(numpy.random.random(100))
l2 = list(numpy.random.random(100))

Und wir sehen hier, dass dict(zip(...bei größeren Datensätzen tatsächlich um etwa 20% schneller läuft.

>>> min(timeit.repeat(lambda: {k: v for k, v in zip(l1, l2)}))
9.698965263989521
>>> min(timeit.repeat(lambda: dict(zip(l1, l2))))
7.9965161079890095
Aaron Hall
quelle
1
Ab Mitte 2019 (Python 3.7.3) finde ich unterschiedliche Timings. %% timeit gibt 1,57 \ pm 0,019 dict(zip(headList, textList))Mikrosekunden für & 1,95 \ pm 0,030 Mikrosekunden für zurück {k: v for k, v in zip(headList, textList)}. Ersteres würde ich aus Gründen der Lesbarkeit und Geschwindigkeit vorschlagen. Offensichtlich kommt dies zum Argument min () vs mean () für timeit.
Mark_Anderson
1
minscheint ein schlechter Weg zu sein, um die Leistung zu vergleichen. Sicherlich meanund / oder maxwären viel nützlichere Indikatoren für den tatsächlichen Gebrauch.
naught101
1
In Python 3.6.8 ist das Diktatverständnis unter Verwendung von Mittelwerten tatsächlich noch schneller, und zwar um etwa 30% für diese kleinen Listen. Bei größeren Listen (10.000 Zufallszahlen) ist der dictAnruf etwa 10% schneller.
naught101
@ naught101 - Ich habe Ihre Kommentare in meiner Antwort angesprochen.
Aaron Hall
3
Die 10.000 Zahlen waren nur ein schneller Weg, um zwei lange Listen einzigartiger Elemente zu generieren. Die Listenerstellung erfolgte außerhalb der Zeitschätzungen. // Warum denkst du, dass gemein oder maximal nutzlos sind? Wenn Sie dies viele Male tun, ist Ihre durchschnittliche Zeit ~ n * Mittelwert und die Obergrenze durch ~ n * max. Ihr Minimum bietet eine Untergrenze, aber die meisten Menschen kümmern sich um die durchschnittliche oder Worst-Case-Leistung. Wenn es eine hohe Varianz gibt, ist Ihr Minimum in den meisten Fällen völlig nicht repräsentativ. Wie ist das Minimum in einem realen Szenario sinnvoller?
naught101
128

Versuche dies:

>>> import itertools
>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> adict = dict(itertools.izip(keys,values))
>>> adict
{'food': 'spam', 'age': 42, 'name': 'Monty'}

In Python 2 ist der Speicherverbrauch im Vergleich zu wirtschaftlicher zip.

Mike Davis
quelle
18
Richtig für Python2, aber in Python 3 zipist der Speicherverbrauch bereits sparsam. docs.python.org/3/library/functions.html#zip In der Tat kann man sehen , dass sixAnwendungen zipin Python 3 zu ersetzen , itertools.izipin 2 Python pythonhosted.org/six .
Pedro Cattori
35
>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> dict(zip(keys, values))
{'food': 'spam', 'age': 42, 'name': 'Monty'}
iny
quelle
28

Sie können auch Wörterbuchverständnisse in Python ≥ 2.7 verwenden:

>>> keys = ('name', 'age', 'food')
>>> values = ('Monty', 42, 'spam')
>>> {k: v for k, v in zip(keys, values)}
{'food': 'spam', 'age': 42, 'name': 'Monty'}
Brendan Berg
quelle
17

Ein natürlicherer Weg ist die Verwendung des Wörterbuchverständnisses

keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')    
dict = {keys[i]: values[i] for i in range(len(keys))}
Polla A. Fattah
quelle
Manchmal ist es der schnellste Weg und manchmal ist es am langsamsten, in ein dictObjekt zu konvertieren . Warum ist es so? Danke, Alter.
Haritsinh Gohil
10

Mit Python 3.x geht es um das Verständnis von Diktaten

keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')

dic = {k:v for k,v in zip(keys, values)}

print(dic)

Mehr zum Diktatverständnis hier , ein Beispiel gibt es:

>>> print {i : chr(65+i) for i in range(4)}
    {0 : 'A', 1 : 'B', 2 : 'C', 3 : 'D'}
kiriloff
quelle
8

Für diejenigen, die einfachen Code benötigen und nicht vertraut sind mit zip:

List1 = ['This', 'is', 'a', 'list']
List2 = ['Put', 'this', 'into', 'dictionary']

Dies kann durch eine Codezeile erfolgen:

d = {List1[n]: List2[n] for n in range(len(List1))}
Exploitprotokoll
quelle
6
scheitert laut, wenn List1länger alsList2
Jean-François Fabre
@ Jean-FrançoisFabre Ist das wirklich wichtig? Was ist der Grund, warum wir zwei Listen mit unterschiedlicher Länge erstellen sollten, um ein Wörterbuch zu erstellen?
Geliebt.von.Jesus
wahrscheinlich nicht, aber danach for n in range(len(List1))ist ein Anti-Muster
Jean-François Fabre
3
  • 2018-04-18

Die beste Lösung ist immer noch:

In [92]: keys = ('name', 'age', 'food')
...: values = ('Monty', 42, 'spam')
...: 

In [93]: dt = dict(zip(keys, values))
In [94]: dt
Out[94]: {'age': 42, 'food': 'spam', 'name': 'Monty'}

Übertragen Sie es:

    lst = [('name', 'Monty'), ('age', 42), ('food', 'spam')]
    keys, values = zip(*lst)
    In [101]: keys
    Out[101]: ('name', 'age', 'food')
    In [102]: values
    Out[102]: ('Monty', 42, 'spam')
Infinitesimalrechnung
quelle
2

Sie können diesen folgenden Code verwenden:

dict(zip(['name', 'age', 'food'], ['Monty', 42, 'spam']))

Stellen Sie jedoch sicher, dass die Länge der Listen gleich ist. Wenn die Länge nicht gleich ist, drehen Sie die Zip-Funktion um die längere.

Akash Nayak
quelle
2

Ich hatte diesen Zweifel, als ich versuchte, ein grafisches Problem zu lösen. Das Problem, das ich hatte, war, dass ich eine leere Adjazenzliste definieren musste und alle Knoten mit einer leeren Liste initialisieren wollte. Dann dachte ich, ich würde prüfen, ob es schnell genug ist. Ich meine, ob es sich lohnt, eine Zip-Operation durchzuführen eher als einfaches Zuweisungsschlüssel-Wert-Paar. Schließlich ist der Zeitfaktor meistens ein wichtiger Eisbrecher. Also habe ich für beide Ansätze eine zeitliche Operation durchgeführt.

import timeit
def dictionary_creation(n_nodes):
    dummy_dict = dict()
    for node in range(n_nodes):
        dummy_dict[node] = []
    return dummy_dict


def dictionary_creation_1(n_nodes):
    keys = list(range(n_nodes))
    values = [[] for i in range(n_nodes)]
    graph = dict(zip(keys, values))
    return graph


def wrapper(func, *args, **kwargs):
    def wrapped():
        return func(*args, **kwargs)
    return wrapped

iteration = wrapper(dictionary_creation, n_nodes)
shorthand = wrapper(dictionary_creation_1, n_nodes)

for trail in range(1, 8):
    print(f'Itertion: {timeit.timeit(iteration, number=trails)}\nShorthand: {timeit.timeit(shorthand, number=trails)}')

Für n_nodes = 10.000.000 bekomme ich,

Iteration: 2.825081646999024 Kurzform: 3.535717916001886

Iteration: 5.051560923002398 Kurzform: 6.255070794999483

Iteration: 6.52859034499852 Kurzform: 8.221581164998497

Iteration: 8.683652416999394 Kurzschrift: 12.599181543999293

Iteration: 11.587241565001023 Kurzform: 15.27298851100204

Iteration: 14.816342867001367 Kurzschrift: 17.162912737003353

Iteration: 16.645022411001264 Kurzschrift: 19.976680120998935

Sie können deutlich sehen, dass nach einem bestimmten Punkt der Iterationsansatz im n-ten Schritt die Zeit übersteigt, die der Kurzansatz im n-1-ten Schritt benötigt.

Mayank Prakash
quelle
1

Hier ist auch ein Beispiel für das Hinzufügen eines Listenwerts in Ihrem Wörterbuch

list1 = ["Name", "Surname", "Age"]
list2 = [["Cyd", "JEDD", "JESS"], ["DEY", "AUDIJE", "PONGARON"], [21, 32, 47]]
dic = dict(zip(list1, list2))
print(dic)

Stellen Sie immer sicher, dass sich Ihr "Schlüssel" (Liste1) immer im ersten Parameter befindet.

{'Name': ['Cyd', 'JEDD', 'JESS'], 'Surname': ['DEY', 'AUDIJE', 'PONGARON'], 'Age': [21, 32, 47]}
Cyd
quelle
0

Lösung als Wörterbuchverständnis mit Aufzählung:

dict = {item : values[index] for index, item in enumerate(keys)}

Lösung wie für Schleife mit Aufzählung:

dict = {}
for index, item in enumerate(keys):
    dict[item] = values[index]
jay123
quelle
0

Sie können es auch mit einer Liste versuchen, die eine Kombination aus zwei Listen ist;)

a = [1,2,3,4]
n = [5,6,7,8]

x = []
for i in a,n:
    x.append(i)

print(dict(zip(x[0], x[1])))
Lakhan Ramawat
quelle
-1

Methode ohne Zip-Funktion

l1 = [1,2,3,4,5]
l2 = ['a','b','c','d','e']
d1 = {}
for l1_ in l1:
    for l2_ in l2:
        d1[l1_] = l2_
        l2.remove(l2_)
        break  

print (d1)


{1: 'd', 2: 'b', 3: 'e', 4: 'a', 5: 'c'}
xiyurui
quelle
Hallo xiyurui, Die Eingabe (l1 und l2) sollte eine Liste sein. Wenn Sie l1 und l2 als Satz zuweisen, wird die Einfügereihenfolge möglicherweise nicht beibehalten. Für mich bekam ich die Ausgabe als {1: 'a', 2: 'c', 3: 'd', 4: 'b', 5: 'e'}
Nursnaaz