Wie kann ich ein Wörterbuch aus separaten Listen von Schlüsseln und Werten erstellen?

Lesezeit: 3 Minuten

Benutzer-Avatar
Guido

Diese möchte ich kombinieren:

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

In ein einziges Wörterbuch:

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

Benutzer-Avatar
Dan Lenski

So was:

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

Voila 🙂 Die paarweise dict Konstrukteur u zip Funktion sind unglaublich nützlich.

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

    – Fernando Wittmann

    28. August 2019 um 15:52 Uhr

  • Ich bin mir nicht sicher, warum du das erwarten würdest, @FernandoWittmann. {thing} ist syntaktischer Zucker, um a zu konstruieren set() ein Element enthält. {*iterable} ist syntaktischer Zucker, um a zu konstruieren set mehrere Elemente enthalten. {k:v} oder {**mapping} Wille konstruieren a dictaber das ist syntaktisch ziemlich unterschiedlich.

    – Dan Lenski

    28. August 2019 um 16:41 Uhr


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

    – Fernando Wittmann

    28. August 2019 um 17:42 Uhr

  • Ich bin hergekommen, falls wir es besser machen können {k:v for k, v in zip(keys, values)}. Es stellt sich heraus, dass wir es können. +1.

    – JG

    23. Januar 2020 um 14:28 Uhr

  • @FernandoWittmann du hast recht, dass es verwirrend ist. {[thing1, thing2, … thingN]} erstellt eine Menge für einen beliebigen Wert von N != 0; aber für N == 0 es schafft ein leeres dictund Sie müssen tun set() um eine leere Menge zu erstellen. Es ist ein etwas unglücklich, und PoLS-Verletzung, Warze von Python, aufgrund der Tatsache, dass Python hatte dict-Literale lange vorher set-Literale.

    – Dan Lenski

    29. Oktober 2020 um 0:14 Uhr


Benutzer-Avatar
Russland muss Putin entfernen

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 leistungsfähigsten, dict Konstrukteur mit zip

new_dict = dict(zip(keys, values))

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

dict(zip(keys, values)) erfordert die einmalige globale Suche jeweils für dict und zipaber es bildet keine unnötigen Zwischendatenstrukturen oder muss sich mit lokalen Suchen in der Funktionsanwendung befassen.

Zweitplatzierter, Diktatverständnis:

Ein enger Nachfolger zur Verwendung des dict-Konstruktors ist die Verwendung der nativen Syntax eines dict-Verständnisses (kein aufführen Verständnis, wie andere es fälschlicherweise ausgedrückt haben):

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

Wählen Sie dies, wenn Sie basierend auf den Schlüsseln oder Werten zuordnen oder filtern müssen.

In Python2, zip gibt eine Liste zurück, um das Erstellen einer unnötigen Liste zu vermeiden, verwenden Sie izip stattdessen (aliased to 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

izip aus itertools wird zip in Python3. izip ist besser als zip für Python 2 (weil 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:

Schauen wir uns die Hilfe an dict Wir sehen, dass es eine Vielzahl von Argumentationsformen braucht:


>>> 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, iterable zu verwenden und gleichzeitig das Erstellen unnötiger 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 zip erstellt lediglich ein iterierbares Objekt:

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

Da wir das Erstellen unnötiger Datenstrukturen vermeiden möchten, möchten wir normalerweise die von Python 2 vermeiden zip (da es eine unnötige Liste erstellt).

Weniger leistungsfähige Alternativen:

Dies ist ein Generatorausdruck, 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 nicht operativer (also unnötiger) 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 sie alle weniger leistungsfähig sind, und sicherlich nicht mehr.

Leistungsbeurteilung:

In 64-Bit-Python 3.8.2, bereitgestellt 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 sogar mit kleinen Sätzen von Schlüsseln und Werten, aber bei größeren Sätzen werden die Leistungsunterschiede größer.

Ein Kommentator sagte:

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

Wir gebrauchen min weil 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 das nichts mit dem zu tun, was wir zu vergleichen versuchen, also müssen wir diese Art von Ergebnissen aus unserer Analyse ausschließen.

Wenn wir benutzten meanwürden solche Ereignisse unsere Ergebnisse stark verfälschen, und wenn wir sie verwenden würden max wir erhalten nur das extremste Ergebnis – dasjenige, das am wahrscheinlichsten von einem solchen Ereignis betroffen ist.

Ein Kommentator sagt auch:

In Python 3.6.8 ist das Diktatverständnis bei Verwendung von Mittelwerten tatsächlich noch schneller, um etwa 30% für diese kleinen Listen. Für größere Listen (10.000 Zufallszahlen) ist die 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 ich wäre nicht überrascht, wenn OS-Hänger dominieren würden, wenn man bedenkt, wie lange es dauern würde, diesen Test auszuführen, was Ihre Zahlen weiter verzerren würde. Und wenn Sie verwenden mean oder max Ich würde Ihre Ergebnisse für bedeutungslos halten.

Lassen Sie uns eine realistischere Größe für unsere Top-Beispiele verwenden:

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

Und das sehen wir hier dict(zip(... läuft in der Tat bei größeren Datensätzen 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

  • Ab Mitte 2019 (Python 3.7.3) finde ich unterschiedliche Timings. %%timeit gibt 1,57 \pm 0,019 Mikrosekunden für zurück dict(zip(headList, textList)) & 1,95 \pm 0,030 Mikrosekunden für {k: v for k, v in zip(headList, textList)}. Ich würde Ersteres wegen der Lesbarkeit und Geschwindigkeit vorschlagen. Offensichtlich kommt dies beim min() vs mean() Argument für timeit an.

    – Mark_Anderson

    2. Juli 2019 um 15:06 Uhr

  • Es scheint, dass Sie sagen, dass das Diktatverständnis am schnellsten ist, aber dann in der Leistungsüberprüfung, dict(zip(keys, values)) sieht schneller aus. Vielleicht hast du vergessen etwas zu aktualisieren?

    – Loisaida Sam Sandberg

    8. April 2020 um 2:57 Uhr

  • Kleine Anmerkung (bei Python 2 EOL weitgehend irrelevant): Sie können verwenden from future_builtins import zip als Alternative zu from itertools import izip as zip Das ist etwas expliziter, wenn es darum geht, den Import in Bezug auf das Erhalten von Python 3 zu beschreiben zip als Ersatz für normale zip. Es ist genau gleichbedeutend mit klar (future_builtins.zip ist selbst nur ein Alias ​​von itertools.izip).

    – ShadowRanger

    29. Oktober 2020 um 18:24 Uhr

Benutzer-Avatar
Mike Davis

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

Benutzer-Avatar
iny

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

Ausgabe:

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

Sie können Wörterbuchverständnisse auch 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'}

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

Benutzer-Avatar
jfs

Wenn Sie Schlüssel oder Werte transformieren müssen, bevor Sie ein Wörterbuch erstellen, a Generatorausdruck könnte verwendet werden. Beispiel:

>>> adict = dict((str(k), v) for k, v in zip(['a', 1, 'b'], [2, 'c', 3])) 

Schau mal Programmieren wie ein Pythonista: Idiomatisches Python.

1157960cookie-checkWie kann ich ein Wörterbuch aus separaten Listen von Schlüsseln und Werten erstellen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy