Python - Rückgabe des ersten N-Schlüssels: Wertepaare aus dict

108

Betrachten Sie das folgende Wörterbuch, d:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

Ich möchte die ersten N Schlüssel: Wert-Paare von d zurückgeben (in diesem Fall N <= 4). Was ist die effizienteste Methode dafür?

Jason Strimpel
quelle
1
Vorsicht. Scheint eine Menge Fehlinformationen in Antworten zu sein. Meine Tests zeigen, dass keine einzige Lösung schneller ist als list(d.items())[:4]. list () ist die zugrunde liegende Implementierung für viele der Antworten.
BSalita

Antworten:

114

Es gibt keine "ersten n" Tasten, da a dictsich nicht daran erinnert, welche Tasten zuerst eingefügt wurden.

Sie können jedoch n beliebige Schlüssel-Wert-Paare erhalten:

n_items = take(n, d.iteritems())

Dies nutzt die Implementierung von takeaus den itertoolsRezepten :

from itertools import islice

def take(n, iterable):
    "Return first n items of the iterable as a list"
    return list(islice(iterable, n))

Sehen Sie, wie es online funktioniert: ideone


Update für Python 3.6

n_items = take(n, d.items())
Mark Byers
quelle
42
Ich glaube, iteritemssollte durch itemsfür Leute auf Python 3 ersetzt werden
Monica Heddneck
1
@MonicaHeddneck, genial, danke, dass du diesen Kommentar hinzugefügt hast.
Karl Baker
11
Anfänger hier - ist take()irgendwo ein Teil der Python-Codebasis? Oder ist es nur die Funktion, die Sie in Ihrer Antwort hier definiert haben? Wenn ich frage, ob es Teil der Codebasis ist, kann ich es nicht finden / importieren. :)
Scott Borden
80

Eine sehr effiziente Möglichkeit, etwas abzurufen, besteht darin, das Verständnis von Listen oder Wörterbüchern mit dem Schneiden zu kombinieren. Wenn Sie die Artikel nicht bestellen müssen (Sie möchten nur n zufällige Paare), können Sie ein Wörterbuchverständnis wie das folgende verwenden:

# Python 2
first2pairs = {k: mydict[k] for k in mydict.keys()[:2]}
# Python 3
first2pairs = {k: mydict[k] for k in list(mydict)[:2]}

Im Allgemeinen ist ein solches Verständnis immer schneller auszuführen als die entsprechende Schleife "für x in y". Wenn Sie mit .keys () eine Liste der Wörterbuchschlüssel erstellen und diese Liste aufteilen, vermeiden Sie außerdem, dass Sie beim Erstellen des neuen Wörterbuchs unnötige Schlüssel berühren.

Wenn Sie die Schlüssel (nur die Werte) nicht benötigen, können Sie ein Listenverständnis verwenden:

first2vals = [v for v in mydict.values()[:2]]

Wenn Sie die Werte nach ihren Schlüsseln sortieren müssen, ist das kein Problem mehr:

first2vals = [mydict[k] for k in sorted(mydict.keys())[:2]]

oder wenn Sie auch die Schlüssel benötigen:

first2pairs = {k: mydict[k] for k in sorted(mydict.keys())[:2]}
Monotasker
quelle
2
Dies ist eine bessere Lösung, wenn Sie N viele Schlüssel: Wert-Paare als Wörterbuch auswählen möchten, nicht als Liste
fermat4214
1
@ fermat4214 Ist es ein Problem, wenn mein gesamtes Wörterbuch ausgedruckt wird, wenn ich einen dieser Befehle ausführe?
Ted Taylor of Life
list (mydict) [: 2] ist verschwenderisch, wenn Sie das Wörterbuch nicht sortieren müssen und nur die ersten beiden Elemente benötigen. Was ist, wenn das Wörterbuch 1 mil kv Paare hat? Das Konvertieren des Ganzen in eine Liste ist teuer. Die Lösung von Mark Byers ist viel besser.
JJ
Dies sollte die Lösung sein!
Günter
14

Pythons dictsind nicht bestellt, daher ist es sinnlos, nach den "ersten N" -Tasten zu fragen.

Die collections.OrderedDictKlasse ist verfügbar, wenn Sie dies benötigen. Sie könnten die ersten vier Elemente effizient als erhalten

import itertools
import collections

d = collections.OrderedDict((('foo', 'bar'), (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')))
x = itertools.islice(d.items(), 0, 4)

for key, value in x:
    print key, value

itertools.isliceMit dieser Option können Sie träge Elemente aus jedem Iterator entfernen. Wenn Sie möchten, dass das Ergebnis wiederverwendbar ist, müssen Sie es in eine Liste oder ähnliches konvertieren:

x = list(itertools.islice(d.items(), 0, 4))
Jeremy Banks
quelle
Sieht nicht faul aus. Dauert 2x länger als `list (d.items ()) [: 4]
BSalita
12
foo = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5, 'f':6}
iterator = iter(foo.items())
for i in range(3):
    print(next(iterator))

Verwandeln Sie die Ansicht (dict_items) in einen Iterator und iterieren Sie sie dann mit next ().

cop4587
quelle
2
Fantastische Antwort, dies ist die einzige Antwort auf dieser Seite, die für mich funktioniert hat und auch lesbar ist. Ich kann auch überprüfen, ob dies mit Python 3 funktioniert, was einige der älteren Antworten nicht zu tun scheinen.
CDahms
7

Habe es hier nicht gesehen. Wird nicht bestellt, sondern syntaktisch am einfachsten, wenn Sie nur einige Elemente aus einem Wörterbuch entnehmen müssen.

n = 2
{key:value for key,value in d.items()[0:n]}
user2623954
quelle
7
Ich habe versucht, Sie Code, aber ich bekomme diesen Fehler: TypeError: 'dict_items' object is not subscriptable {key:value for key,value in stocks.items()[0:n]} (Aktien ist der Name meines Wörterbuchs)
Moondra
2
@Moondra - Muss in die Liste konvertiert werden, bevor Wörterbuchelemente durchlaufen werden. Über dem Code funktioniert die Zeile, wenn {Schlüssel: Wert für Schlüssel, Wert in Liste (d.items ()) [0: n]}
Rajesh Mappu
{A: N für (A, N) in [x für x in d.items ()] [: 4]}
farid khafizov
5

Um die Top-N-Elemente aus Ihrem Python-Wörterbuch zu erhalten, können Sie die folgende Codezeile verwenden:

list(dictionaryName.items())[:N]

In Ihrem Fall können Sie Folgendes ändern:

list(d.items())[:4]
thevatsalsaglani
quelle
3

Siehe PEP 0265 zum Sortieren von Wörterbüchern. Verwenden Sie dann den oben genannten iterierbaren Code.

Wenn Sie mehr Effizienz bei den sortierten Schlüssel-Wert-Paaren benötigen. Verwenden Sie eine andere Datenstruktur. Das heißt, eine, die die sortierte Reihenfolge und die Schlüsselwertzuordnungen beibehält.

Z.B

import bisect

kvlist = [('a', 1), ('b', 2), ('c', 3), ('e', 5)]
bisect.insort_left(kvlist, ('d', 4))

print kvlist # [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
Silbermarmelade
quelle
3

In py3 reicht dies aus

{A:N for (A,N) in [x for x in d.items()][:4]}

{'a': 3, 'b': 2, 'c': 3, 'd': 4}

farid khafizov
quelle
2

füge einfach eine Antwort mit zip hinzu,

{k: d[k] for k, _ in zip(d, range(n))}
Peter Li
quelle
1

Dies hängt davon ab, was in Ihrem Fall am effizientesten ist.

Wenn Sie nur eine halbzufällige Stichprobe eines riesigen Wörterbuchs fooverwenden möchten , verwenden foo.iteritems()und verwenden Sie so viele Werte, wie Sie benötigen. Dies ist eine verzögerte Operation, bei der die Erstellung einer expliziten Liste von Schlüsseln oder Elementen vermieden wird.

Wenn Sie zuerst Schlüssel sortieren müssen, führt kein Weg daran vorbei, keys = foo.keys(); keys.sort()oder sorted(foo.iterkeys())Sie müssen eine explizite Liste von Schlüsseln erstellen. Dann schneiden oder durchlaufen ersten N keys.

Übrigens, warum interessiert Sie der "effiziente" Weg? Haben Sie Ihr Programm profiliert? Wenn Sie dies nicht getan haben, verwenden Sie zuerst den offensichtlichen und leicht verständlichen Weg. Die Chancen stehen gut, dass es ziemlich gut läuft, ohne zu einem Engpass zu werden.

9000
quelle
Dies war eine Anwendung für ein Finanzprogramm, und ich versuche, jede Codezeile so effizient wie möglich zu erstellen. Ich habe das Programm nicht profiliert und bin damit einverstanden, dass dies wahrscheinlich kein Flaschenhals sein wird, aber ich möchte standardmäßig nach effizienten Lösungen fragen. Danke für die Antwort.
Jason Strimpel
0

Sie können dies auf verschiedene Arten angehen. Wenn die Reihenfolge wichtig ist, können Sie dies tun:

for key in sorted(d.keys()):
  item = d.pop(key)

Wenn die Bestellung kein Problem darstellt, können Sie dies tun:

for i in range(4):
  item = d.popitem()
gddc
quelle
Im ersten Ausschnitt sollten Sie es wahrscheinlich valueeher nennen als itemaus Gründen der Klarheit.
Agf
0

Das Wörterbuch behält keine Reihenfolge bei. Bevor Sie also die ersten N Schlüsselwertpaare auswählen, können Sie es sortieren.

import operator
d = {'a': 3, 'b': 2, 'c': 3, 'd': 4}
d=dict(sorted(d.items(),key=operator.itemgetter(1),reverse=True))
#itemgetter(0)=sort by keys, itemgetter(1)=sort by values

Jetzt können wir die obersten 'N'-Elemente abrufen: Mit der folgenden Methodenstruktur:

def return_top(elements,dictionary_element):
    '''Takes the dictionary and the 'N' elements needed in return
    '''
    topers={}
    for h,i in enumerate(dictionary_element):
        if h<elements:
            topers.update({i:dictionary_element[i]})
    return topers

Um die Top 2 Elemente zu erhalten, verwenden Sie einfach diese Struktur:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4}
d=dict(sorted(d.items(),key=operator.itemgetter(1),reverse=True))
d=return_top(2,d)
print(d)
Jyothish Arumugam
quelle
0

Wählen Sie für Python 3 und höher zuerst n Paare aus

n=4
firstNpairs = {k: Diction[k] for k in list(Diction.keys())[:n]}
Shivpe_R
quelle
0

Betrachten Sie ein Diktat

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

from itertools import islice
n = 3
list(islice(d.items(),n))

islice wird den Trick machen :) hoffe es hilft!

Vivek Ananthan
quelle
0

Das mag nicht sehr elegant sein, funktioniert aber für mich:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

x= 0
for key, val in d.items():
    if x == 2:
        break
    else:
        x += 1
        # Do something with the first two key-value pairs
Thorsten Stehlik
quelle
0

Ich habe einige der obigen Antworten ausprobiert und festgestellt, dass einige davon versionabhängig sind und in Version 3.7 nicht funktionieren.

Ich stelle auch fest, dass seit 3.6 alle Wörterbücher nach der Reihenfolge geordnet sind, in der Elemente eingefügt werden.

Obwohl Wörterbücher seit 3.6 bestellt wurden, scheinen einige der Anweisungen, die Sie für geordnete Strukturen erwarten, nicht zu funktionieren.

Die Antwort auf die OP-Frage, die für mich am besten funktioniert hat.

itr = iter(dic.items())
lst = [next(itr) for i in range(3)]
Mark Kortink
quelle
Zu lst = list(d.items())[:N]
Ihrer Information