1734 Stimmen

Wie kann ich zwei Listen in ein Wörterbuch umwandeln?

Ich möchte sie kombinieren:

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

In ein einziges Wörterbuch:

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

2904voto

Dan Lenski Punkte 72055

Utilisez zip zur Erstellung einer Liste von (key, value) Tupel, dann wenden Sie die dict Konstrukteur:

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

Ausgabe:

{'a': 1, 'b': 2, 'c': 3}

29 Stimmen

Es ist erwähnenswert, dass dictionary = {zip(keys, values)} wird nicht funktionieren. Sie müssen explizit deklarieren als dict(...)

30 Stimmen

Ich weiß nicht, warum Sie das erwarten, @FernandoWittmann. {thing} ist ein syntaktischer Zucker zur Konstruktion einer set() die ein Element enthalten. {*iterable} ist ein syntaktischer Zucker zur Konstruktion einer set die mehrere Elemente enthält. {k:v} o {**mapping} wird konstruieren eine dict , aber das ist syntaktisch ganz anders.

15 Stimmen

Danke für den Kommentar, Dan. Sie haben recht. Meine Verwirrung ist entstanden, weil ich normalerweise die sintax {} für Wörterbücher. In der Tat, wenn wir versuchen type({}) die Ausgabe ist dict . Aber in der Tat, wenn wir versuchen type({thing}) dann lautet die Ausgabe set .

239voto

Stellen Sie sich vor, Sie haben:

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

Wie lässt sich das folgende Wörterbuch am einfachsten erstellen?

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

Am leistungsfähigsten, dict Konstrukteur mit zip

new_dict = dict(zip(keys, values))

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

dict(zip(keys, values)) erfordert das einmalige globale Nachschlagen für jede dict y zip Es werden jedoch keine unnötigen Zwischendateistrukturen gebildet, und in der Funktionsanwendung müssen keine lokalen Suchvorgänge durchgeführt werden.

Zweiter Platz, Diktatverständnis:

Der zweite Weg zur Verwendung des dict-Konstruktors ist die Verwendung der nativen Syntax eines dict-Verständnisses (nicht eines リスト Verständnis, wie es andere fälschlicherweise formuliert haben):

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

Wählen Sie diese Option, wenn Sie eine Zuordnung oder einen Filter auf der Grundlage von Schlüsseln oder Werten benötigen.

In Python 2, zip eine Liste zurückgibt. Um die Erstellung einer unnötigen Liste zu vermeiden, verwenden Sie izip stattdessen (aliased to zip kann Code-Änderungen reduzieren, wenn Sie auf Python 3 umsteigen).

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

izip von itertools wird zip in Python 3. izip ist besser als zip für Python 2 (weil es die unnötige Listenerstellung vermeidet), und ideal für 2.6 oder darunter:

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

Ergebnis für alle Fälle:

In allen Fällen:

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

Erläuterung:

Wenn wir uns die Hilfe auf dict sehen wir, dass es eine Vielzahl von Argumentationsformen 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 ist die Verwendung einer Iterable, wobei die Erstellung unnötiger Datenstrukturen vermieden wird. In Python 2 erzeugt zip eine unnötige Liste:

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

In Python 3 würde die Entsprechung lauten:

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

und Python 3's zip erzeugt lediglich ein iterierbares Objekt:

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

Da wir vermeiden wollen, unnötige Datenstrukturen zu erstellen, wollen wir in der Regel Python 2's zip (da es eine unnötige Liste erstellt).

Weniger leistungsfähige Alternativen:

Dies ist ein Generator-Ausdruck, der an den dict-Konstruktor übergeben wird:

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

oder gleichwertig:

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

Und dies ist ein Listenverständnis, das an den dict-Konstruktor übergeben wird:

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

In den ersten beiden Fällen wird eine zusätzliche Schicht von nicht-operativen (und damit unnötigen) Berechnungen über die Zip-Iterable gelegt, und im Fall des Listenverständnisses wird unnötigerweise eine zusätzliche Liste erstellt. Ich würde erwarten, dass alle von ihnen weniger performant sind, und sicherlich nicht mehr so.

Leistungsüberprüfung:

In 64 Bit Python 3.8.2 von Nix, auf 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 bei kleinen Mengen von Schlüsseln und Werten, aber bei größeren Mengen werden die Leistungsunterschiede größer.

Ein Kommentator sagte:

min scheint ein schlechter Weg zu sein, um Leistung zu vergleichen. Sicherlich mean und/oder max wären viel nützlichere Indikatoren für die tatsächliche Nutzung.

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

Wenn sich das Betriebssystem aus irgendeinem Grund aufhängt, hat das nichts mit dem zu tun, was wir zu vergleichen versuchen, also müssen wir diese Art von Ergebnissen von unserer Analyse ausschließen.

Wenn wir die mean Diese Art von Ereignissen würde unsere Ergebnisse stark verfälschen, und wenn wir die max erhalten wir nur das extremste Ergebnis - dasjenige, das am ehesten von einem solchen Ereignis betroffen ist.

Ein Kommentator sagt auch:

In Python 3.6.8 ist das Diktat-Verständnis bei Verwendung von Mittelwerten tatsächlich immer noch schneller, und zwar um etwa 30 % für diese kleinen Listen. Bei größeren Listen (10k Zufallszahlen) ist das dict Anruf ist etwa 10 % schneller.

Ich nehme an, wir meinen dict(zip(... mit 10k Zufallszahlen. Das klingt nach einem ziemlich ungewöhnlichen Anwendungsfall. Es macht Sinn, dass die direktesten Aufrufe in großen Datensätzen dominieren würden, und es würde mich nicht überraschen, wenn OS-Hänger dominieren, wenn man bedenkt, wie lange es dauern würde, diesen Test auszuführen, was Ihre Zahlen weiter verzerrt. Und wenn Sie Folgendes verwenden mean ou max Ich würde Ihre Ergebnisse als bedeutungslos betrachten.

Nehmen wir eine realistischere Größe für unsere oberen Beispiele:

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

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

>>> 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

2 Stimmen

Ab Mitte 2019 (Python 3.7.3) finde ich unterschiedliche Zeitangaben. %%timeit liefert 1,57 \pm 0,019microsec für dict(zip(headList, textList)) & 1.95 \pm 0,030 Mikrosekunden für {k: v for k, v in zip(headList, textList)} . Ich würde aus Gründen der Lesbarkeit und der Geschwindigkeit die erste Variante vorschlagen. Offensichtlich geht es hier um das Argument min() vs. mean() für timeit.

0 Stimmen

Es scheint, als ob Sie sagen, dass das Diktatverständnis am schnellsten ist, aber dann in der Leistungskontrolle, dict(zip(keys, values)) sieht schneller aus. Vielleicht haben Sie vergessen, etwas zu aktualisieren?

1 Stimmen

Kleine Anmerkung (weitgehend irrelevant angesichts des Auslaufens von Python 2): Sie können from future_builtins import zip als Alternative zu from itertools import izip as zip die den Import etwas genauer beschreibt, um die Python 3 zip als Ersatz für reguläre zip . Es ist genau gleichwertig, um klar zu sein ( future_builtins.zip ist selbst nur ein Alias von itertools.izip ).

138voto

Mike Davis Punkte 1403

Versuchen Sie 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 es auch sparsamer im Speicherverbrauch im Vergleich zu zip .

23 Stimmen

Richtig für Python2, aber in Python 3, zip ist bereits sparsam im Speicherverbrauch. docs.python.org/3/Bibliothek/Funktionen.html#zip In der Tat können Sie sehen, dass six 用途 zip in Python 3 zu ersetzen itertools.izip in Python 2 pythonhosted.org/six .

0 Stimmen

Abgelehnte Antwort

41voto

iny Punkte 7005
keys = ('name', 'age', 'food')
values = ('Monty', 42, 'spam')
out = dict(zip(keys, values))

Ausgabe:

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

31voto

Brendan Berg Punkte 1880

Sie können in Python 2.7 auch Wörterbuchkomplexe verwenden:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X