Wie iteriere ich in Python über ein Wörterbuch in sortierter Schlüsselreihenfolge?

211

Es gibt eine vorhandene Funktion, die wie folgt endet d: Ein Wörterbuch:

return d.iteritems()

Das gibt einen unsortierten Iterator für ein bestimmtes Wörterbuch zurück. Ich möchte einen Iterator zurückgeben, der die nach Schlüssel sortierten Elemente durchläuft . Wie mache ich das?

Mike
quelle

Antworten:

171

Habe dies nicht sehr ausführlich getestet, funktioniert aber in Python 2.5.2.

>>> d = {"x":2, "h":15, "a":2222}
>>> it = iter(sorted(d.iteritems()))
>>> it.next()
('a', 2222)
>>> it.next()
('h', 15)
>>> it.next()
('x', 2)
>>>

Wenn Sie es gewohnt sind, for key, value in d.iteritems(): ...anstelle von Iteratoren zu arbeiten, funktioniert dies weiterhin mit der obigen Lösung

>>> d = {"x":2, "h":15, "a":2222}
>>> for key, value in sorted(d.iteritems()):
>>>     print(key, value)
('a', 2222)
('h', 15)
('x', 2)
>>>

Verwenden Sie in Python 3.x d.items()anstelle von d.iteritems(), um einen Iterator zurückzugeben.

jpp
quelle
29
Verwenden Sie .items()anstelle von iteritems(): Wie @Claudiu sagte, funktionieren Iteritems nicht für Python 3.x, sind jedoch items()in Python 2.6 verfügbar.
Remi
40
Das ist nicht offensichtlich. Tatsächlich items()wird eine Liste erstellt und daher Speicher verwendet, während im iteritems()Wesentlichen kein Speicher verwendet wird. Was zu verwenden ist, hängt hauptsächlich von der Größe des Wörterbuchs ab. Darüber hinaus 2to3übernimmt das automatische Konvertierungstool Python 2 in Python 3 ( ) automatisch die Konvertierung von iteritems()nach items(), sodass Sie sich darüber keine Gedanken machen müssen.
Eric O Lebigot
5
@HowerHell verwenden Sie eine, collections.OrderedDictdann sortieren Sie einmal und erhalten Artikel immer in sortierter Reihenfolge.
Mark Harviston
9
Aber @EOL, auch wenn iteritems()kein Speicher verwendet wird, muss alles in den Speicher gezogen werden sorted(), damit es keinen Unterschied zwischen der Verwendung von items()und iteritems()hier in Bezug auf den Speicher gibt .
Richard
8
@Richard: Zwar müssen alle Elemente in den Speicher gezogen werden, sie werden jedoch zweimal mit (in der von und in der sortierten Liste zurückgegebenen Liste) und nur einmal mit ( nur in der sortierten Liste) gespeichert . items()items()iteritems()
Eric O Lebigot
83

Verwenden Sie die sorted()Funktion:

return sorted(dict.iteritems())

Wenn Sie einen tatsächlichen Iterator über die sortierten Ergebnisse wünschen, da sorted()eine Liste zurückgegeben wird, verwenden Sie:

return iter(sorted(dict.iteritems()))
Greg Hewgill
quelle
Das schlägt für mich fehl: <Typ 'Ausnahmen.TypError'>: iter () hat einen Nicht-Iterator vom Typ 'Liste' zurückgegeben
Mike
Das liegt wahrscheinlich daran, dass Sie "dict" als Variablennamen verwenden. "dict" ist eigentlich der Typname von Wörterbüchern. Verwenden Sie hier einfach einen anderen Namen wie "mydict" und voila.
utku_karatas
1
Funktioniert immer noch nicht. Sind Sie positiv sortiert () gibt einen anderen Iterator zurück als eine reguläre Liste?
Mike
Wann und wo tritt diese Ausnahme auf? Sie können problemlos über eine Liste iterieren
1
Einverstanden, hüpfen. Ich glaube nicht, dass ich jemals .next () direkt aufrufe, außer wenn ich Zeilen in Dateien überspringe. Unsere iter (sorted (dict.iteritems ())) - Lösung erstellt ohnehin eine Kopie des gesamten Diktats im Speicher in der "sorted" - Phase, sodass der primäre Iterator-Vorteil verloren zu sein scheint :)
39

Die Schlüssel eines Diktats werden in einer Hashtabelle gespeichert, so dass dies ihre "natürliche Reihenfolge" ist, dh pseudozufällig. Jede andere Bestellung ist ein Konzept des Verbrauchers des Diktats.

sorted () gibt immer eine Liste zurück, kein Diktat. Wenn Sie ein dict.items () übergeben (das eine Liste von Tupeln erzeugt), wird eine Liste von Tupeln [(k1, v1), (k2, v2), ...] zurückgegeben, die in einer Schleife verwendet werden können in gewisser Weise wie ein Diktat, aber es ist sowieso kein Diktat !

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

print foo
>>> {'a': 1, 'c': 3, 'b': 2}

print foo.items()
>>> [('a', 1), ('c', 3), ('b', 2)]

print sorted(foo.items())
>>> [('a', 1), ('b', 2), ('c', 3)]

Das Folgende fühlt sich wie ein Diktat in einer Schleife an, ist es aber nicht, es ist eine Liste von Tupeln, die in k, v entpackt werden:

for k,v in sorted(foo.items()):
    print k, v

Ungefähr gleichbedeutend mit:

for k in sorted(foo.keys()):
    print k, foo[k]
Peter Rowell
quelle
Okay, aber ich möchte kein Diktat oder eine Liste, ich möchte einen Iterator. Wie zwinge ich es, ein Iterator zu sein?
Mike
2
sorted(foo.keys())ist besser als das Äquivalent sorted(foo), da Wörterbücher ihre Schlüssel zurückgeben, wenn sie wiederholt werden (mit dem Vorteil foo.keys(), dass sie möglicherweise nicht gezwungen werden, die Zwischenliste zu erstellen - je nachdem, wie sorted()sie für iterable implementiert werden).
Eric O Lebigot
Ich k in sorted(foo.keys()):for k,v in sorted(foo.items()):sorted(foo.keys())
frage
1
@CrandellWS: Die Zeitfrage lässt sich am besten mit dem Python timeit- Modul beantworten .
Peter Rowell
1
@frank - Kurze Antwort: Nein. Ein Diktat ist ein Array, bei dem der tatsächliche Schlüssel ein Hash des Werts des angegebenen Schlüssels ist. Obwohl einige Implementierungen ziemlich vorhersehbar sind und einige diesen Vertrag sogar abschließen, zähle ich bei der Hash-Bestellung auf nichts . Weitere Informationen zum Verhalten von 3.6+ finden Sie in diesem Beitrag . Beachten Sie insbesondere die erste Antwort.
Peter Rowell
31

Gregs Antwort ist richtig. Beachten Sie, dass Sie dies in Python 3.0 tun müssen

sorted(dict.items())

wie iteritemswird weg sein.

Claudiu
quelle
Das schlägt für mich fehl: <Typ 'Ausnahmen.TypError'>: iter () hat einen Nicht-Iterator vom Typ 'Liste' zurückgegeben
Mike
3
"Verwenden Sie keine Autos, weil wir in Zukunft Hoverboards haben werden"
JJ
7

Sie können jetzt auch OrderedDictin Python 2.7 verwenden:

>>> from collections import OrderedDict
>>> d = OrderedDict([('first', 1),
...                  ('second', 2),
...                  ('third', 3)])
>>> d.items()
[('first', 1), ('second', 2), ('third', 3)]

Hier haben Sie die neue Seite für die Version 2.7 und die OrderedDict-API .

Caumons
quelle
Dadurch werden Schlüsselwerte in der Reihenfolge zurückgegeben, in der sie eingefügt wurden - nicht in einer sortierten Reihenfolge (dh alphabetisch).
Tony Suffolk 66
5

Im Allgemeinen kann man ein Diktat so sortieren:

for k in sorted(d):
    print k, d[k]

Fügen Sie für den speziellen Fall in der Frage mit einem "Drop-in-Replacement" für d.iteritems () eine Funktion wie die folgende hinzu:

def sortdict(d, **opts):
    # **opts so any currently supported sorted() options can be passed
    for k in sorted(d, **opts):
        yield k, d[k]

und so ändert sich die Endzeile von

return dict.iteritems()

zu

return sortdict(dict)

oder

return sortdict(dict, reverse = True)
Pythonlarry
quelle
5
>>> import heapq
>>> d = {"c": 2, "b": 9, "a": 4, "d": 8}
>>> def iter_sorted(d):
        keys = list(d)
        heapq.heapify(keys) # Transforms to heap in O(N) time
        while keys:
            k = heapq.heappop(keys) # takes O(log n) time
            yield (k, d[k])


>>> i = iter_sorted(d)
>>> for x in i:
        print x


('a', 4)
('b', 9)
('c', 2)
('d', 8)

Diese Methode hat immer noch eine O (N log N) -Sortierung. Nach einem kurzen linearen Heapify werden die Elemente jedoch in sortierter Reihenfolge ausgegeben, was sie theoretisch effizienter macht, wenn Sie nicht immer die gesamte Liste benötigen.

Jamylak
quelle
4

Wenn Sie nach der Reihenfolge sortieren möchten, in der Elemente anstelle der Reihenfolge der Schlüssel eingefügt wurden, sollten Sie einen Blick auf Pythons Sammlungen werfen. OrderedDict . (Nur Python 3)

Gecco
quelle
3

sortiert gibt eine Liste zurück, daher Ihr Fehler, wenn Sie versuchen, darüber zu iterieren. Da Sie jedoch kein Diktat bestellen können, müssen Sie sich mit einer Liste befassen.

Ich habe keine Ahnung, was der größere Kontext Ihres Codes ist, aber Sie könnten versuchen, der resultierenden Liste einen Iterator hinzuzufügen. so vielleicht?:

return iter(sorted(dict.iteritems()))

Natürlich werden Sie jetzt Tupel zurückbekommen, weil sortiert Ihr Diktat in eine Liste von Tupeln verwandelt hat

Beispiel: Sagen Sie, Ihr Diktat war: {'a':1,'c':3,'b':2} Sortiert verwandelt es in eine Liste:

[('a',1),('b',2),('c',3)]

Wenn Sie also tatsächlich über die Liste iterieren, erhalten Sie (in diesem Beispiel) ein Tupel zurück, das aus einer Zeichenfolge und einer Ganzzahl besteht, aber zumindest können Sie darüber iterieren.

pcn
quelle
2

Angenommen, Sie verwenden CPython 2.x und haben ein großes Wörterbuch mydict, dann wird die Verwendung von sortiert (mydict) langsam sein, da sortiert eine sortierte Liste der Schlüssel von mydict erstellt.

In diesem Fall sollten Sie sich mein bestelltes Dikt-Paket ansehen, das eine C-Implementierung von enthält sorteddict in C enthält. Insbesondere, wenn Sie die sortierte Liste der Schlüssel in verschiedenen Phasen (dh Anzahl der Elemente) der Lebensdauer der Wörterbücher mehrmals durchgehen müssen.

http://anthon.home.xs4all.nl/Python/ordereddict/

Anthon
quelle