Seite 1 von 1

Liste -> Mehrfacheinträge eliminieren und zählen

Verfasst: Donnerstag 5. März 2009, 16:30
von christine
Hallo,

diesmal wollte ich es eigendlich alleine schaffen....
Aber ich komme einfach nicht weiter.

Ich habe eine dyn. generierte Liste.
In dieser Liste können Einträge mehrfach vorkommen.
beispiel_liste = ['Hund','Katze','Hund','Maus','Hund']
Ich möcht die Listeneinträge in eine Datei schreiben, aber nicht so:

Hund
Hund
Hund

sondern

Hund : Trefferanzahl=3
Katze: Trefferanzahl=1....


ich habe jetzt schon eingie Ansätze versucht, aber nichts klappt so wirklich.

Ich weiss nicht wie ich diese Abfrage umsetzen soll.
Habe es mit gleichen Listen versucht (und rausgefunden, das kopierte Listen ganz anders reagieren als "gleiche" Listen -> Referenz auf Liste?!)

Idee:

Liste1 = B,B,B
Liste2 = B,B,B
vgl. Liste1[0] mit Liste2[0] ->True -> Zähler = Zähler + 1, del Liste2[0]

Liste1 = B,B,B
Liste2 = X,B,B

...ihr versteht sicher was ich meine, aber es funktioniert nicht, da der Zustand von Liste2 (glaube ich) so ist:

Liste2 = B,B und Liste1 jetzt auf den index[1] von Liste 2 Springt, also das zweite und letzte B

OK, hoffentlich nicht zu chaotisch formuliert
Hier mein letzter (missglückter) versuch:

Code: Alles auswählen

liste_1 = ['1','1','3','1']
liste_2 = ['1','1','3','1']

for zahl1 in liste_1:
    a=1
    liste_3 = []
    print "\n\nzalh1 ist:",zahl1,"\n"
    for zahl2 in liste_2:
        print "Vergleiche zalh1:",zahl1,"\n"
        print "mit zalh2:",zahl2,"\n---------"
        if zahl1 == zahl2:
            print "die Zahlen sind gleich\n---"
            liste_3.append(zahl1)
            print "liste_3:",liste_3,"\n"
            liste_2.remove(zahl2)
            print "liste_2:",liste_2,"\n"
        else:
            print "die Zahlen sind ungleich\n"
bei diesem Versuch, wollte ich alle gleichen Einträge in Liste_3 schreiben
und dann die Anzahl über len() oder ähnlich ausgeben, aber bei mehr als einem Eintrag bekomme ich len(n-1) -> hoffe ich habe das richtig beobachtet

würde mich über eure Tipps freuen :)

Grüße,christine

Verfasst: Donnerstag 5. März 2009, 16:36
von Nocta
Du kannst doch einfach die Werte in einem Dictionary speichern:

Code: Alles auswählen

x = {Hund: 3, Something: 1, ...}
Gehst du halt einfach die Liste durch und addest entweder einen neuen Key oder inkrementierst, falls der Key schon vorhanden ist, den Wert des Keys ;)
Ich hab mir jetzt nicht alles genau durchgelesen, aber am Anfang stand ja, dass du eigentlich sowas haben willst.

Edit:
Habe es mit gleichen Listen versucht (und rausgefunden, das kopierte Listen ganz anders reagieren als "gleiche" Listen -> Referenz auf Liste?!)
http://www.python-forum.de/topic-17228.html
Da wird glaube ich sowas in der Richtung erklärt, wie du das meinst, wenn ich den Thread richtig in Erinnerung habe.

Verfasst: Donnerstag 5. März 2009, 16:50
von helduel
Moin christine,

defaultdict ist hier wohl das richtige:

Code: Alles auswählen

from collections import defaultdict
pets = ["Hund", "Katze", "Maus", "Hund", "Hund", "Katze"]
counted = defaultdict(int)
for pet in pets:
    counted[pet] += 1
counted
# defaultdict(<type 'int'>, {'Katze': 2, 'Hund': 3, 'Maus': 1})
Gibt es einen Key nicht schon im Dictionary, dann ruft defaultdict den übergebenen Konstruktor auf (hier int) und weißt den zurückgegebenen Wert dem fehlenden Key zu.

Gruß,
Manuel

Verfasst: Donnerstag 5. März 2009, 17:07
von Nocta
Hm, cool, mit defaultdict geht das ja _noch_ einfacher, kannte ich noch gar nicht :)

Wenn du dann die Keys und die zugehörigen Werte wieder auslesen willst, musst du dann nur noch folgendes machen:

Code: Alles auswählen

for i in counted.keys():
    print i, counted[i]

Verfasst: Donnerstag 5. März 2009, 17:10
von helduel
Nocta hat geschrieben:Hm, cool, mit defaultdict geht das ja _noch_ einfacher, kannte ich noch gar nicht :)

Wenn du dann die Keys und die zugehörigen Werte wieder auslesen willst, musst du dann nur noch folgendes machen:

Code: Alles auswählen

for i in counted.keys():
    print i, counted[i]
In deinem Beispiel kannst du dir auch das ".keys()" sparen ;-).

Verfasst: Donnerstag 5. März 2009, 17:18
von Nocta
Ups, ja stimmt :p

Verfasst: Donnerstag 5. März 2009, 18:21
von BlackJack
Und wenn man eh beides haben will, kann man auch gleich über die Paare iterieren:

Code: Alles auswählen

for animal, count in counted.iteritems():
    print '%s: %d' % (animal, count)

Verfasst: Donnerstag 5. März 2009, 20:15
von hendrikS
Als Alternative zu defaultdict kann man auch mit set arbeiten. Ist Geschmackssache.

z.Bsp. so:

Code: Alles auswählen

pets = ["Hund", "Katze", "Maus", "Hund", "Hund", "Katze"]
for pet in set(pets): print pet, pets.count(pet)

Verfasst: Donnerstag 5. März 2009, 21:15
von BlackJack
@hendrikS: Wer mag denn bitteschön quadratische Laufzeit, wenn er lineare haben kann!?

Verfasst: Donnerstag 5. März 2009, 21:42
von hendrikS
Ich hab das Zeitargument von BlackJack mal kurz gecheckt mit einer Hunde, Katze, Maus Liste von ungefähr 20000 Einträgen. Ist bei beiden Lösungen etwa identisch. Möglicherweise habe ich aber nicht genuegend Testfälle gehabt.
Weiss nicht genau wie Du auf quadratisch kommst?

Verfasst: Donnerstag 5. März 2009, 21:50
von Hyperion
hendrikS hat geschrieben: Weiss nicht genau wie Du auf quadratisch kommst?
Weil Du in der äußeren Schleife die Anzahl an pets durchläufst und dann in der inneren bei jedem einzelnen Durchlauf auch! -> Laufzeit quadratisch!

Verfasst: Freitag 6. März 2009, 00:55
von Leonidas
hendrikS hat geschrieben:Ich hab das Zeitargument von BlackJack mal kurz gecheckt mit einer Hunde, Katze, Maus Liste von ungefähr 20000 Einträgen. Ist bei beiden Lösungen etwa identisch.
Dann war dein ``n`` zu klein. Schau her was es für tolle Caches gibt und wie gut Python optimiert ist :)

Verfasst: Freitag 6. März 2009, 11:08
von hendrikS
Ich habe noch mal n'bisschen performance mit timeit gecheckt.
Also speziell, wenn die Anzahl verschiedener Elemente zunimmt (so ab >6) wir die Performance meiner Lösung stetig schlechter :cry: .
Na ja. Sei's drum. Die schnellere Lösung sollte immer den Vorzug haben. Also klares Votum fuer defaultdict.

Verfasst: Freitag 6. März 2009, 11:47
von helduel
hendrikS hat geschrieben:Die schnellere Lösung sollte immer den Vorzug haben.
Nicht unbedingt.

Code: Alles auswählen

import this

Verfasst: Freitag 6. März 2009, 12:06
von christine
Hey,
ihr seid echt super!
Ich nehme jetzt die Lösung von helduel.
Musste aber erst noch von 2.4 auf 2.5 umsteigen :wink:

Ich finde die ganze Diskussion super hilfreich.
Mit set() hatte ich auch schon etwas herumversucht, aber auf eine richtige Lösung bin ich da von selbst nicht gekommen :roll:
Oft weiss ich nicht wie was syntaktisch umzusetzen ist.
Und nat. auch nicht was es alles für Module und Einsatzmöglichkeiten gibt.

Also, vielen vielen Dank @ all

Verfasst: Freitag 6. März 2009, 17:58
von Nocta
Mal ne Frage, wenn ich dieses Defaultdict jetzt sortiert nach Häufigkeit ausgeben will, gibt es dann noch was einfacheres als dies hier?

Code: Alles auswählen

for i in sorted([(x, y) for x, y in counted.iteritems()], lambda x, y: y[1] - x[1]):
    print i[0], i[1]
Ich finde die Lösung zwar nicht schlecht und auch gut verständlich, aber vielleicht kann mir ja wieder jemand etwas neues aufzeigen, wie das so oft hier im Forum passiert.

Verfasst: Freitag 6. März 2009, 20:17
von lunar

Code: Alles auswählen

for key, item in sorted(counted.iteritems(), key=itemgetter(1)):
    print(key, item, sep=': ')
"itemgetter()" kommt aus dem "operator"-Modul.

Verfasst: Montag 9. März 2009, 15:20
von christine
Hallo,
ich sortiere meine Ausgabe auch:

Code: Alles auswählen

counted = defaultdict(int) 
for ergebnisWort in ergebnisListeDerAbfrage:
     counted[ergebnisWort] += 1 

sortierung = sorted((value, key) for (key, value) in counted.iteritems())
sortierung.reverse()
for key, value in sortierung:
     print "Treffer: %d %s" % (key, value)
Erhalte dann folgende Ausgabe:

Code: Alles auswählen

Treffer: 4 Bekleidungsgeschäfts 
Treffer: 2 Weisungsrecht 
Treffer: 2 Geschäftslokal 
Treffer: 2 Geschäfte 
Treffer: 1 Gewerbemiete 
Treffer: 1 Geschäftsraummietvertrag 
8)