2009-02-04 10 views
112

Ich habe über 10 Millionen Werte, die ich brauche von Nachschlagtabelle in irgendeiner Art zu setzen, so dass ich frage mich, was effizienter eine Liste oder dict sein würde?Python: Liste vs Dict für Nachschautabelle

Ich weiß, dass Sie so etwas wie dies für beides kann:

if something in dict_of_stuff: 
    pass 

und

if something in list_of_stuff: 
    pass 

Mein Gedanke ist, die dict wird schneller sein und effizienter zu gestalten.

Danke für Ihre Hilfe.

EDIT 1
Wenig mehr Informationen darüber, was ich versuche zu tun. Euler Problem 92. Ich mache eine Nachschlagetabelle, um zu sehen, ob ein berechneter Wert bereits berechnet wurde.

EDIT 2
Effizienz zum Nachschlagen.

EDIT 3
Es sind keine Werte mit dem Wert assosiated ... so wäre ein Satz besser sein?

+1

Effizienz in Bezug auf was? Einfügen? Sieh nach oben? Speicherverbrauch? Suchen Sie nach reinem Wert, oder sind Metadaten damit verbunden? – truppo

+0

Als eine Randnotiz benötigen Sie keine 10 Millionen Liste oder ein Diktat für dieses spezielle Problem, sondern ein viel kleineres. – sfotiadis

+0

Was wäre, wenn die Tabelle ein Tupel anstelle einer Liste wäre? Sind Tupel-Elemente gehashed oder handelt es sich nur um eine unveränderliche Liste? – RufusVS

Antwort

154

Geschwindigkeit

Lookups in Listen O (n), Lookups in der Wörterbuch amortisieren O (1), in Bezug auf die Anzahl der Elemente in die Datenstruktur. Wenn Sie keine Werte zuordnen müssen, verwenden Sie Sets.

Speicher

Beide Wörterbücher und Sätze benutzen Hashing und sie verwenden viel mehr Speicher als nur für Objektspeicher. Laut A.M. Kuchling in Beautiful Code, die Implementierung versucht, den Hash zu 2/3 voll zu halten, so dass Sie ziemlich viel Speicher verschwenden könnten.

Wenn Sie im laufenden Betrieb keine neuen Einträge hinzufügen (was Sie aufgrund Ihrer aktualisierten Frage tun), kann es sinnvoll sein, die Liste zu sortieren und die binäre Suche zu verwenden. Dies ist O (log n) und ist wahrscheinlich für Strings langsamer, unmöglich für Objekte, die keine natürliche Ordnung haben.

+0

Listensortierung ist O (n log n) – SilentGhost

+6

Ja, aber es ist ein einmaliger Vorgang, wenn sich der Inhalt nie ändert . Die binäre Suche ist O (log n). –

+0

OTOH, werden 10 Millionen Ganzzahlen, was, 40 Millionen Bytes? Wenn der Hash zu 2/3 voll ist, geht das auf 60 Millionen, und es wird Overhead geben (jeder weiß wie viel?), Aber das Ganze sollte in ein paar hundert MB Speicher passen. Es war vielleicht vor zehn Jahren ein Problem, aber es ist jetzt nicht wirklich. –

6

wenn Daten sind einzigartig set() wird das effizienteste, aber zwei - dict (die auch Einzigartigkeit erfordert, oops :)

+1

nicht wirklich ... Daten müssen auch für das Diktat eindeutig sein. – nosklo

+0

Ich habe festgestellt, wenn ich sah meine Antwort geschrieben%) – SilentGhost

+1

@SilentGhost, wenn die Antwort falsch ist, warum nicht löschen? Schade für die Upvotes, aber das passiert (nun, _happened_) –

32

A dict ist eine Hash-Tabelle, so dass es wirklich schnell das finden Schlüssel. Also zwischen Diktat und Liste wäre das Diktat schneller. Aber wenn Sie keinen assoziativen Wert haben, ist es sogar besser, einen Satz zu verwenden. Es ist eine Hash-Tabelle ohne den Teil "Tabelle".


EDIT: für Ihre neue Frage, JA, wäre ein Satz besser. Erstellen Sie einfach 2 Sätze, einen für Sequenzen, die mit 1 enden und andere für die mit 89 beendeten Sequenzen. Ich habe dieses Problem mit Sets erfolgreich gelöst.

5

Sie wollen ein Diktat.

Für (unsortierte) Listen in Python, die Operation "in" benötigt O (n) Zeit --- nicht gut, wenn Sie eine große Menge an Daten haben. Ein dict hingegen ist eine Hash-Tabelle, so dass Sie O (1) Lookup-Zeit erwarten können.

Wie andere bemerkt haben, könnten Sie stattdessen einen Satz (einen speziellen Diktattyp) wählen, wenn Sie nur Schlüssel statt Schlüssel/Wert-Paare haben.

Verwandte:

  • Python wiki: Informationen über die Zeitkomplexität von Python Container-Operationen.
  • SO: Python Behälter Betriebszeit und Speicher Komplexitäten
+1

Auch für sortierte Listen ist "in" O (n). –

+1

Für eine verkettete Liste, ja --- aber "Listen" in Python sind, was die meisten Menschen Vektoren nennen würde, die indizierten Zugriff in O (1) und eine Suche in O (log n) bereitstellen, wenn sortiert. – zweiterlinde

+0

Wollen Sie sagen, dass der auf eine sortierte Liste angewendete "in" -Operator besser funktioniert als wenn er auf einen unsortierten angewendet wird (für die Suche nach einem zufälligen Wert)?(Ich denke nicht, ob sie intern als Vektoren oder als Knoten in einer Linked-List implementiert sind.) – martineau

0

Sie müssen nicht wirklich 10 Millionen Werte in der Tabelle speichern, also ist es auch keine große Sache.

Hinweis: Denken Sie daran, wie groß Ihr Ergebnis nach der ersten Quadratsummenoperation sein kann. Das größtmögliche Ergebnis wird viel kleiner als 10 Millionen sein ...

24

set() ist genau das, was Sie wollen. O (1) Suchvorgänge und kleiner als ein Diktat.

21

habe ich einige Benchmarking und es stellt sich heraus, dass dict schneller als beide Liste ist und für große Datenmengen eingestellt, läuft Python 2.7.3 auf einem i7 CPU auf Linux:

  • python -mtimeit -s 'd=range(10**7)' '5*10**6 in d'

    10 Schleifen, am besten von 3: 64,2 msec pro Schleife

  • python -mtimeit -s 'd=dict.fromkeys(range(10**7))' '5*10**6 in d'

    10000000 Schleifen, am besten von 3: 0,075 9 usec pro Schleife

  • python -mtimeit -s 'from sets import Set; d=Set(range(10**7))' '5*10**6 in d'

    1000000 Schleifen, am besten von 3: 0,262 usec pro Schleife

Wie Sie sehen können, dict ist wesentlich schneller als Liste und etwa 3-mal schneller als Set . In einigen Anwendungen möchten Sie vielleicht dennoch für die Schönheit der Umgebung wählen. Und wenn die Datensätze wirklich klein sind (< 1000 Elemente), funktionieren die Listen ziemlich gut.

+0

Sollte es nicht genau das Gegenteil sein? Liste: 10 * 64.2 * 1000 = 642000 Usec, dict: 10000000 * 0.0759 = 759000 Usec und set: 1000000 * 0.262 = 262000 usec ... also Sätze sind die schnellsten, gefolgt von der Liste und mit dict als letzte in Ihrem Beispiel. Oder fehlt mir etwas? – andzep

+0

... aber die Frage ist für mich hier: Was misst diese Zeit eigentlich? Nicht die Zugriffszeit für eine bestimmte Liste, dict oder set, sondern viel mehr, die Zeit und die Schleifen _create_ die Liste, dict, set und schließlich einen Wert zu finden und zuzugreifen. Hat das also mit der Frage überhaupt zu tun? ... Es ist interessant, aber ... – andzep

+5

@andzep, Sie irren sich, die '-s'-Option ist die Einrichtung der' Zeit'-Umgebung, d.h. es zählt nicht in der Gesamtzeit. Die Option "-s" wird nur einmal ausgeführt. Auf Python 3.3, bekomme ich diese Ergebnisse: Gen (Bereich) -> 0.229 Usec, Liste -> 157 ms, dict -> 0.0806 Usec, Set -> 0.0807 Usec. Leistung einstellen und diktieren ist gleich. Dict dauert jedoch etwas länger zu initialisieren als gesetzt (Gesamtzeit 13.580s v. 11.803s) – sleblanc

Verwandte Themen