Fügt einem Wörterbuch neue Schlüssel hinzu, während vorhandene Werte inkrementiert werden

8

Ich verarbeite eine CSV-Datei und zähle die eindeutigen Werte von Spalte 4. Bis jetzt habe ich diese drei Wege codiert. Der eine verwendet "if key in dictionary", der zweite den KeyError und der dritte "DefaultDictionary". Zum Beispiel (wo x [3] ist der Wert aus der Datei und "a" ist ein Wörterbuch):

Erster Weg:

%Vor%

Zweiter Weg:

%Vor%

Dritter Weg:

%Vor%

Meine Frage ist: welcher Weg ist effizienter ... sauberer ... besser ... usw. Oder gibt es einen besseren Weg? Beide Wege funktionieren und geben die gleiche Antwort, aber ich dachte, ich würde den Schwarmgeist als einen Lernfall anzapfen.

Danke -

    
Count Boxer 27.10.2010, 18:32
quelle

5 Antworten

6

Verwenden Sie collections.Counter . Counter ist syntaktischer Zucker für defaultdict(int) , aber das Beste daran ist, dass es im Konstruktor ein iterables akzeptiert und somit einen zusätzlichen Schritt speichert (ich nehme an, dass alle obigen Beispiele in eine for-Schleife eingeschlossen sind.)

%Vor%

Vor der Einführung von collections.Counter war collections.defaultdict das idiomatische für diese Aufgabe, also für Benutzer & lt; 2.7, benutze defaultdict .

%Vor%     
Steven Rumbalski 27.10.2010, 18:42
quelle
6

Sie haben gefragt, was effizienter ist. Angenommen, Sie sprechen von Ausführungsgeschwindigkeit: Wenn Ihre Daten klein sind, ist das egal. Wenn es groß und typisch ist, wird der Fall "schon existiert" viel öfter passieren als der Fall "nicht im Diktat". Diese Beobachtung erklärt einige der Ergebnisse.

Im Folgenden finden Sie einen Code, der mit dem Modul timeit verwendet werden kann, um die Geschwindigkeit ohne Datei-Lese-Overhead zu untersuchen. Ich habe mir die Freiheit genommen, eine fünfte Methode hinzuzufügen, die nicht unkompetent ist und auf jedem Python ab mindestens 1.5.2 (getestet) läuft.

%Vor%

Typischer Lauf (im Fenster "Eingabeaufforderung" von Windows XP):

%Vor%

Hier sind die Ergebnisse (ms pro Schleife):

%Vor%

Noch ein Timing-Versuch:

%Vor%

Die Geschwindigkeit von Counter ist möglicherweise darauf zurückzuführen, dass sie teilweise in Python-Code implementiert ist, während defaultdict vollständig in C (mindestens in 2.7) ist.

Beachten Sie, dass Counter() NICHT nur "syntaktischer Zucker" für defaultdict(int) ist - es implementiert ein vollständiges Objekt bag aka multiset - weitere Informationen finden Sie in den Dokumenten. Sie können Sie davon abhalten, das Rad neu zu erfinden, wenn Sie eine ausgefallene Nachbearbeitung benötigen. Wenn Sie nur Dinge zählen möchten, verwenden Sie defaultdict .

Update als Antwort auf eine Frage von @Steven Rumbalski: "" "Ich bin gespannt, was passiert, wenn Sie das iterable in den Counter-Konstruktor verschieben: d = Counter (iterable)? Habe Python 2.6 und kann es nicht testen.) "" "

tally6: macht nur d = Count(iterable); return d , benötigt 60.0 ms

Sie könnten die Quelle (collections.py im SVN-Repository) sehen ... hier ist meine Python27\Lib\collections.py , wenn iterable keine Mapping-Instanz ist:

%Vor%

Haben Sie diesen Code schon einmal gesehen? Es gibt eine ganze Menge Carry-On, nur um Code aufzurufen, der in Python 1.5.2 :-O

ausgeführt werden kann     
John Machin 27.10.2010 20:37
quelle
1
%Vor%     
SilentGhost 27.10.2010 18:34
quelle
0

Da Sie keinen Zugriff auf den Counter haben, ist Ihr dritter Ansatz die beste Wahl. Es ist viel sauberer und einfacher zu lesen. Außerdem hat es nicht die fortwährende Prüfung (und Verzweigung), die die ersten beiden Ansätze haben, was es effizienter macht.

    
chrisaycock 27.10.2010 18:39
quelle
0

Verwenden Sie setdefault .

%Vor%

setdefault erhält den Wert des angegebenen Schlüssels ( x[3] in diesem Fall) oder, falls dieser nicht existiert, den angegebenen Wert ( 0 in diesem Fall).

    
kindall 27.10.2010 23:00
quelle

Tags und Links