Python-Wörterbuch: Liste der Werte für die Liste der Schlüssel abrufen


179

Gibt es eine integrierte / schnelle Möglichkeit, eine Liste von Schlüsseln für ein Wörterbuch zu verwenden, um eine Liste der entsprechenden Elemente zu erhalten?

Zum Beispiel habe ich:

>>> mydict = {'one': 1, 'two': 2, 'three': 3}
>>> mykeys = ['three', 'one']

Wie kann ich mykeysdie entsprechenden Werte im Wörterbuch als Liste abrufen?

>>> mydict.WHAT_GOES_HERE(mykeys)
[3, 1]

Antworten:


204

Ein Listenverständnis scheint ein guter Weg zu sein, dies zu tun:

>>> [mydict[x] for x in mykeys]
[3, 1]

1
Wenn mydictes sich um einen Funktionsaufruf handelt (der ein Diktat zurückgibt), wird die Funktion mehrmals aufgerufen, oder?
Endolith

1
@endolith Ja, das wird es
Eric Romrell

107

Ein paar andere Möglichkeiten als list-comp:

  • Liste erstellen und Ausnahme auslösen, wenn Schlüssel nicht gefunden wird: map(mydict.__getitem__, mykeys)
  • Liste erstellen mit Nonewenn Schlüssel nicht gefunden:map(mydict.get, mykeys)

Alternativ kann using operator.itemgetterein Tupel zurückgeben:

from operator import itemgetter
myvalues = itemgetter(*mykeys)(mydict)
# use `list(...)` if list is required

Hinweis : Gibt in Python3 mapeher einen Iterator als eine Liste zurück. Verwenden Sie list(map(...))für eine Liste.


54

Ein kleiner Geschwindigkeitsvergleich:

Python 2.7.11 |Anaconda 2.4.1 (64-bit)| (default, Dec  7 2015, 14:10:42) [MSC v.1500 64 bit (AMD64)] on win32
In[1]: l = [0,1,2,3,2,3,1,2,0]
In[2]: m = {0:10, 1:11, 2:12, 3:13}
In[3]: %timeit [m[_] for _ in l]  # list comprehension
1000000 loops, best of 3: 762 ns per loop
In[4]: %timeit map(lambda _: m[_], l)  # using 'map'
1000000 loops, best of 3: 1.66 µs per loop
In[5]: %timeit list(m[_] for _ in l)  # a generator expression passed to a list constructor.
1000000 loops, best of 3: 1.65 µs per loop
In[6]: %timeit map(m.__getitem__, l)
The slowest run took 4.01 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 853 ns per loop
In[7]: %timeit map(m.get, l)
1000000 loops, best of 3: 908 ns per loop
In[33]: from operator import itemgetter
In[34]: %timeit list(itemgetter(*l)(m))
The slowest run took 9.26 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 739 ns per loop

Listenverständnis und Itemgetter sind also die schnellsten Wege, dies zu tun.

UPDATE: Bei großen Zufallslisten und Karten hatte ich etwas andere Ergebnisse:

Python 2.7.11 |Anaconda 2.4.1 (64-bit)| (default, Dec  7 2015, 14:10:42) [MSC v.1500 64 bit (AMD64)] on win32
In[2]: import numpy.random as nprnd
l = nprnd.randint(1000, size=10000)
m = dict([(_, nprnd.rand()) for _ in range(1000)])
from operator import itemgetter
import operator
f = operator.itemgetter(*l)
%timeit f(m)
%timeit list(itemgetter(*l)(m))
%timeit [m[_] for _ in l]  # list comprehension
%timeit map(m.__getitem__, l)
%timeit list(m[_] for _ in l)  # a generator expression passed to a list constructor.
%timeit map(m.get, l)
%timeit map(lambda _: m[_], l)
1000 loops, best of 3: 1.14 ms per loop
1000 loops, best of 3: 1.68 ms per loop
100 loops, best of 3: 2 ms per loop
100 loops, best of 3: 2.05 ms per loop
100 loops, best of 3: 2.19 ms per loop
100 loops, best of 3: 2.53 ms per loop
100 loops, best of 3: 2.9 ms per loop

In diesem Fall ist der klare Gewinner f = operator.itemgetter(*l); f(m)und klarer Außenseiter : map(lambda _: m[_], l).

UPDATE für Python 3.6.4:

import numpy.random as nprnd
l = nprnd.randint(1000, size=10000)
m = dict([(_, nprnd.rand()) for _ in range(1000)])
from operator import itemgetter
import operator
f = operator.itemgetter(*l)
%timeit f(m)
%timeit list(itemgetter(*l)(m))
%timeit [m[_] for _ in l]  # list comprehension
%timeit list(map(m.__getitem__, l))
%timeit list(m[_] for _ in l)  # a generator expression passed to a list constructor.
%timeit list(map(m.get, l))
%timeit list(map(lambda _: m[_], l)
1.66 ms ± 74.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
2.1 ms ± 93.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.58 ms ± 88.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.36 ms ± 60.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.98 ms ± 142 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.7 ms ± 284 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
3.14 ms ± 62.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Die Ergebnisse für Python 3.6.4 sind also fast gleich.


15

Hier sind drei Möglichkeiten.

Erhöhen, KeyErrorwenn der Schlüssel nicht gefunden wird:

result = [mapping[k] for k in iterable]

Standardwerte für fehlende Schlüssel.

result = [mapping.get(k, default_value) for k in iterable]

Fehlende Schlüssel überspringen.

result = [mapping[k] for k in iterable if k in mapping]

found_keys = mapping.keys() & iterablegibt TypeError: unsupported operand type(s) for &: 'list' and 'list'auf Python 2.7; `found_keys = [Schlüssel für Schlüssel in Mapping.keys (), wenn Schlüssel in iterable] funktioniert am besten
NotGaeL

10

Versuche dies:

mydict = {'one': 1, 'two': 2, 'three': 3}
mykeys = ['three', 'one','ten']
newList=[mydict[k] for k in mykeys if k in mydict]
print newList
[3, 1]

7

Versuche dies:

mydict = {'one': 1, 'two': 2, 'three': 3}
mykeys = ['three', 'one'] # if there are many keys, use a set

[mydict[k] for k in mykeys]
=> [3, 1]

@ PeterDeGlopper du bist verwirrt. items()wird bevorzugt, es muss keine zusätzliche Suche durchgeführt werden, hier gibt es keine len(mydict)*len(mykeys)Operation! (Beachten Sie, dass ich ein Set benutze)
Óscar López

@ ÓscarLópez Ja, Sie überprüfen jedes Element des Wörterbuchs. iteritems liefert sie erst, wenn Sie sie benötigen, sodass keine Zwischenliste erstellt wird. Sie führen jedoch weiterhin 'k in mykeys' (order len (mykeys), da es sich um eine Liste handelt) für jedes k in mydict aus. Völlig unnötig im Vergleich zu dem einfacheren Listenverständnis, das nur über mykeys läuft.
Peter DeGlopper

@ InspectorG4dget @PeterDeGlopper Der Mitgliedschaftsvorgang wird über die mykeyskonstante Zeit abgeschrieben. Ich verwende einen Satz, keine Liste
Óscar López

2
Das Konvertieren der OP-Liste in eine Menge macht sie zumindest linear, aber sie ist immer noch linear in Bezug auf die falsche Datenstruktur und verliert die Reihenfolge. Betrachten Sie den Fall eines 10k-Wörterbuchs und 2 Schlüsseln in mykeys. Ihre Lösung führt 10k-Mitgliedschaftstests durch, verglichen mit zwei Wörterbuchsuchen für das einfache Listenverständnis. Im Allgemeinen kann man davon ausgehen, dass die Anzahl der Schlüssel kleiner als die Anzahl der Wörterbuchelemente ist - und wenn dies nicht der Fall ist, werden bei Ihrem Ansatz wiederholte Elemente weggelassen.
Peter DeGlopper


1

Pandas tut dies sehr elegant, obwohl das Verständnis von Listen immer technisch pythonischer sein wird. Ich habe momentan keine Zeit für einen Geschwindigkeitsvergleich (ich komme später wieder und stelle ihn ein):

import pandas as pd
mydict = {'one': 1, 'two': 2, 'three': 3}
mykeys = ['three', 'one']
temp_df = pd.DataFrame().append(mydict)
# You can export DataFrames to a number of formats, using a list here. 
temp_df[mykeys].values[0]
# Returns: array([ 3.,  1.])

# If you want a dict then use this instead:
# temp_df[mykeys].to_dict(orient='records')[0]
# Returns: {'one': 1.0, 'three': 3.0}

-1

Oder einfach, mydict.keys()das ist ein integrierter Methodenaufruf für Wörterbücher. Auch erkunden mydict.values()und mydict.items().

// Ah, OP Post hat mich verwirrt.


5
Die integrierten Methoden sind nützlich, enthalten jedoch keine Liste der entsprechenden Elemente aus einer bestimmten Liste von Schlüsseln. Diese Antwort ist keine richtige Antwort auf diese spezielle Frage.
Stenix

-1

Nach dem Schließen von Python: Effiziente Methode zum Erstellen einer Liste aus Diktatwerten mit einer bestimmten Reihenfolge

Abrufen der Schlüssel ohne Erstellen der Liste:

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import collections


class DictListProxy(collections.Sequence):
    def __init__(self, klist, kdict, *args, **kwargs):
        super(DictListProxy, self).__init__(*args, **kwargs)
        self.klist = klist
        self.kdict = kdict

    def __len__(self):
        return len(self.klist)

    def __getitem__(self, key):
        return self.kdict[self.klist[key]]


myDict = {'age': 'value1', 'size': 'value2', 'weigth': 'value3'}
order_list = ['age', 'weigth', 'size']

dlp = DictListProxy(order_list, myDict)

print(','.join(dlp))
print()
print(dlp[1])

Die Ausgabe:

value1,value3,value2

value3

Welches der Reihenfolge in der Liste entspricht


-2
reduce(lambda x,y: mydict.get(y) and x.append(mydict[y]) or x, mykeys,[])

falls es Schlüssel gibt, die nicht diktiert sind.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.