häufigkeiten von strings

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
picknicker187
User
Beiträge: 3
Registriert: Mittwoch 21. Februar 2007, 23:40

hi,

ich habe listen mit strings und würde gerne zählen wie oft jeder string in den listen vorkommt und am ende dann die string sortiert nach häufigkeit mit der entsprechenden anzahl ausgeben. also zb: liste: ('bla', 'bla', 'blub, 'hallo')
2:bla
1: blub
1:hallo
ich dachte ich könnte ein string beim ersten fund in ein dict schreiben und als value die 1 dazu, bei jedem weiteren vorkommen dann den value um 1 erhöhen und am schluss dann das dict nach values sortiert ausgeben. aber ich weiss leider nicht wie ich einen value um 1 erhöhen kann und irgendwie macht mir das ganze den eindruck als ob es dafür eine wesentlich einfachere lösung geben müsste. hat jenand eine idee?

gruß und danke,
michi
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Das geht schon so wie du beschrieben hast:

Code: Alles auswählen

In [8]: words = ('bla', 'bla', 'blub', 'hallo')
In [9]: frequencies = dict()
In [10]: for word in words:
   ....:     frequencies[word] = frequencies.get(word, 0) + 1
   ....:
In [11]: frequencies
Out[11]: {'hallo': 1, 'bla': 2, 'blub': 1}
Wie du jetzt die Worte nach Häufigkeit sortierst, darfst du selbst rausfinden ;)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Auf die schnelle zusammengehackt:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-


def sort_elements_to_frequency(iterable, reverse=True):
    freq_dict = dict()
    order = list()
    for elem in iterable:
        try:
            freq_dict[elem] += 1
        except KeyError, error:
            freq_dict[elem] = 1
    
    for k, v in freq_dict.iteritems():
        order.append('%s\0%s' % (v, k))
    order.sort(reverse=reverse)
    return [x.replace('\0', ': ') for x in order]


if __name__ == '__main__':
    li = ['blubb', '43', 'foobar', 'barfoo', 'blubb', '43', 'foobar', 'barfoo',
         'blubb', '43', '43']

    print sort_elements_to_frequency(li)
Ist nicht die performanteste Lösung.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Verbesserte und schnellerer Version.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-


def sort_elements_to_frequency(iterable, reverse=True):
    freq_dict = dict()
    order = list()
    for elem in iterable:
        if elem in freq_dict:
            freq_dict[elem] += 1
        else:
            freq_dict[elem] = 1
    
    for k, v in freq_dict.iteritems():
        order.append('%s: %s' % (v, k))
    order.sort(reverse=reverse)
    return order
    
if __name__ == '__main__':
    li = ['blubb', '43', 'foobar', 'barfoo', 'blubb', '43', 'foobar', 'barfoo',
         'blubb', '43', '43']

    print sort_elements_to_frequency(li)
BTW: Der ``in`` test sollte schneller sein als ein try...except.

EDIT:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-


def sort_elements_to_frequency(iterable, reverse=True):
    freq_dict = dict()
    order = list()
    for elem in iterable:
        if elem in freq_dict:
            freq_dict[elem] += 1
        else:
            freq_dict[elem] = 1
    
    order = [{v: k} for k, v, in freq_dict.iteritems()]
    order.sort(reverse=reverse)
    return order
    
if __name__ == '__main__':
    li = ['blubb', '43', 'foobar', 'barfoo', 'blubb', '43', 'foobar', 'barfoo',
         'blubb', '43', '43']

    print sort_elements_to_frequency(li)
[{4: '43'}, {3: 'blubb'}, {2: 'foobar'}, {2: 'barfoo'}]
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Ich will auch ;-)

Code: Alles auswählen

>>> baselist = ["aal", "berta", "aal", "zoo", "zoo", "aal"]
>>> words = frozenset(baselist)
>>> words
frozenset(['aal', 'berta', 'zoo'])
>>> counted = {}
>>> for word in words:
...     counted[word] = baselist.count(word)
...     
>>> counted
{'aal': 3, 'berta': 1, 'zoo': 2}
>>> 

# Nachtrag:
>>> counted_list = counted.items()
>>> counted_list
[('aal', 3), ('berta', 1), ('zoo', 2)]
>>> import operator
>>> counted_list.sort(key = operator.itemgetter(1))
>>> counted_list
[('berta', 1), ('zoo', 2), ('aal', 3)]
>>>
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

OK, ich fasse das mal zu einem Programm zusammen. Es wird aber sicher nicht so schnell sein wie das Beispiel von Leonidas, da er die Liste nur einmal durchläuft.

Code: Alles auswählen

import operator

baselist = ["aal", "berta", "aal", "zoo", "zoo", "aal"]
words = frozenset(baselist)

counted_words = []
for word in words:
    counted_words.append(
        (word, baselist.count(word))
    )
counted_words.sort(key = operator.itemgetter(1))

for item in counted_words:
    print "%-10s %i" % item
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hier noch einer... damit der Gedanke nicht verloren geht und ich endlich mal ein Beispiel für itertools.groupby habe. :-)

Code: Alles auswählen

import operator
import itertools

baselist = ["aal", "berta", "aal", "zoo", "zoo", "aal"]
sorted_baselist = sorted(baselist)

counted_words = []
for word, items in itertools.groupby(sorted_baselist):
    counted_words.append((word, len(list(items))))

counted_words.sort(key = operator.itemgetter(1))

for item in counted_words:
    print "%-10s %i" % item
mfg
Gerold
:-)

PS: Falls jemand fragt... Ja, man kann alles komplizierter machen, als es sein müsste. :twisted:
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

Na dann geb ich auch noch meine Senf dazu ^^

Code: Alles auswählen

>>> tmp
l = ["bla", "bla", "blub", "hallo"]

for i in l:
tmp = list()
for i in l:
    if (l.count(i), i) not in tmp: tmp.append((l.count(i), i))

for c, i in tmp:
    print str(c)+':', i

:roll: :roll: :roll:
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ja, bei so etwas kann man sich einfach nicht zuückhalten :D:

Code: Alles auswählen

data = ["a", "b", "c", "a", "a", "b", "c", "d", "b"]
r = [(data.count(x), x) for x in set(data)]
r.sort()
r = [(x,y) for y,x in r]
Da hätte ich einen ja fast noch intuitiven Einzeiler:D:

Code: Alles auswählen

data = ["a", "b", "c", "a", "a", "b", "c", "d", "b"]
r = [(x,y) for y,x in sorted([(data.count(x), x) for x in set(data)])]
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

@sape: dein erstes Beispiel im zweiten Post sortiert falsch.
@nkoehring, EyDu: euer Code hat AFAICS quadratische Laufzeit.

Leonidas' Lösung ist am geschicktesten IMO.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

@birkenfeld:
Aber Leonidas Lösung sortiert nicht, das überlässt er dem Benutzer :-)

Mit der quadratischen Laufzeit sehe ich das bei mir etwas anders:
Bilden der Menge in: m = O(n*log n)
Sortieren: s = O(n * log n)
Und das Tauschen, was eigentlich nicht nötig ist: t = O(n)

Macht dann insgesamt (da sequentiell): m + s + t = O(n*log n)

Wir wollen ja nicht schätzen, sondern rechnen :wink:

EDIT: Da habe ich wohl das Zählen vergessen, dann ist es natürlich quadratische Laufzeit. :roll:
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

birkenfeld hat geschrieben:@sape: dein erstes Beispiel im zweiten Post sortiert falsch.
Warum :? Weil '2: foobar' vor '2: barfoo' kommt? Ich weiß auch nicht warum ``sort`` das nicht richtig macht:

Code: Alles auswählen

li = ['2: barfoo', '3: blubb', '2: foobar', '4: 43']
li.sort(reverse=True)
print li
Ansonsten sehe ich nicht wo falsch sortiert wird:
Zweiter Post erstes Beispiel:
['4: 43', '3: blubb', '2: foobar', '2: barfoo']

Zweiter Post zweites Beispiel:
[{4: '43'}, {3: 'blubb'}, {2: 'foobar'}, {2: 'barfoo'}]

Leonidas' Lösung ist am geschicktesten IMO.
Die Lösung sortiert aber nicht.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

sape hat geschrieben:
Leonidas' Lösung ist am geschicktesten IMO.
Die Lösung sortiert aber nicht.
Aber sie berechnet die Häufigkeit am klarsten - ohne Exceptions und stattdessen mit Defaultwerten. Den Weg habe ich mir mal von BlackJack abgeschaut.

Meine Lösung ist insofern genial, da sie dem OP auch etwas zu tun überlässt, so dass er auch etwas lernen kann. Ergo: Edukativ :P

Nun gut, wir könnten die Lösungen (für beide Probleme: Berechnen und Sortieren) auch später in einer Wikiseite zusammentragen, so wie es in [wiki]Anzahl der Es in einem String[/wiki] der Fall ist.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Leonidas hat geschrieben:Aber sie berechnet die Häufigkeit am klarsten - ohne Exceptions und stattdessen mit Defaultwerten
Seh' ich auch so, zum Zählen der Vorkommnisse scheint mir dies auch die eleganteste Variante, aber Ziel muss es ja sein, das gesamte Problem mit möglichst undurchsichtigen und einzeiligen List-Comprehensions zu lösen :D
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

EyDu hat geschrieben:aber Ziel muss es ja sein, das gesamte Problem mit möglichst undurchsichtigen und einzeiligen List-Comprehensions zu lösen :D
Man könnte auch noch Threads rauspacken, so wie blackbird bei den Es.

Ich glaube wir haben den OP nun sehr effektiv vergrault indem wir aus seinem Thread einen Wettbewerb für Obfuscated Python gemacht haben 8) picknicker187, bist du noch dran?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Leonidas hat geschrieben:Man könnte auch noch Threads rauspacken, so wie blackbird bei den Es.
Nee, nee, so war meine Lösung nicht gemeint, sondern eher ein Vorschlag wie man es noch machen könnte. Und ich muss sagen, dieser Thread hat doch ganz brauchbare Variationen hervorgebracht, wie man an so ein Problem herangehen kann, auch wenn man sie eventuell als Einsteiger nicht sofort versteht.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

sape hat geschrieben:
birkenfeld hat geschrieben:@sape: dein erstes Beispiel im zweiten Post sortiert falsch.
Warum :? Weil '2: foobar' vor '2: barfoo' kommt?
Nein, weil "10: barfoo" vor "1: barfoo" kommt.
Ansonsten sehe ich nicht wo falsch sortiert wird:
Zweiter Post erstes Beispiel:
['4: 43', '3: blubb', '2: foobar', '2: barfoo']

Zweiter Post zweites Beispiel:
[{4: '43'}, {3: 'blubb'}, {2: 'foobar'}, {2: 'barfoo'}]
Ja, mit einstelligen Zahlen funktioniert es schon. Mit mehrstelligen nicht.
Leonidas' Lösung ist am geschicktesten IMO.
Die Lösung sortiert aber nicht.
Ja, das ist trivial anzuhängen.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

birkenfeld hat geschrieben:
sape hat geschrieben:
birkenfeld hat geschrieben:@sape: dein erstes Beispiel im zweiten Post sortiert falsch.
Warum :? Weil '2: foobar' vor '2: barfoo' kommt?
Nein, weil "10: barfoo" vor "1: barfoo" kommt.
Hi,

das Problem kenne ich nur zu gut. Der Doppelpunkt hat den Characterwert 58, Zahlen aber kleinere. Dadurch werden kürzere Zahlen nach unten sortiert. Wenn es nur um die Ausgabe geht, kann man die Zahlen vorn mit Leerzeichen auffüllen, die stehen dann oben:

Code: Alles auswählen

iMax = max(frequencies)
l = ["%*s: %s" % (iMax, iAnzahl, sString) for sString, iAnzahl in frequencies.items()]
l.sort()
Dass foobar vor barfoo kommt ist logisch, wenn man rückwärts sortiert. :-)

Grüße,
Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Ja, man kann auch über China nach Amerika fliegen. Man kann aber auch einfach die Zahlen als Integers belassen und sortieren, anstatt sie vorher in Strings umzuwandeln.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Birkenfeld und Michael, danke für euren Hinweiß, das hatte ich nicht beachtet.

EDIT: Hab nochmal meine zweite variante (im zweiten post) getestet und die scheint zu gehen :D

Zweite vom zweiten Post:
[{10: 'barfoo'}, {4: '43'}, {3: 'blubb'}, {1: 'foobar'}]
Antworten