Werte in Liste zählen und mehrmals vorgekommene Werte ausgeben

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.
Antworten
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

Hallo

Ich wollte heute schnell eine kleine Funktion zum Zählen der Vorkommnisse von Werten in einer Liste und anschließende Rückgabe von Werten, die x mal vorgekommen sind, schreiben. Aus "schnell" wurde eher nichts und der Code wurde auch länger als erwartet.

Ist der Code unten ein brauchbarer Anfang für die Erstellung der Funktion?

Code: Alles auswählen

from random import randrange

LENGTH = 200

measurements = [randrange(0, 50) for _ in range(0, LENGTH)]
occurrences = dict()

for i in range(LENGTH):
    measurements.count([i])
    current_value = measurements[i]

    if current_value not in occurrences.keys():
        occurrences[current_value] = 1
    else:
        occurrences[current_value] += 1

result = occurrences.copy()

for key, value in occurrences.items():
    if value <= 2:
        del result[key]

print(result)
Gruß
Atalanttore
Benutzeravatar
__blackjack__
User
Beiträge: 14044
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Atalanttore: Nicht wirklich. Die erste Zeile in der Schleife macht nichts ausser sinnlos Zeit verbrauchen. Du machst nichts mit dem Rückgabewert, der zudem *immer* 0 ist. Denn eine Liste mit dem Index kommt ja gar nicht in `measurements` vor. Selbst wenn – was soll das?

Das nächste ist der unnötige Umweg über einen Index. Man kann in Python direkt über die Elemente einer Liste iterieren.

Zum Zählen ist `collections.Counter` angebracht. Wenn man es aus irgendwelchen unbedingt selbst schreiben will, dann wenigstens ein `collections.defaultdict` mit `int` als ”factory”.

Und statt eine Kopie zu erstellen und dann aus dem Original alle Einträge mit einerm Wert < 2 zu löschen, wäre es weniger umständlich einfach ein neues Wörterbuch zu erstellen, wo nur die Einträge drin sind, die man behalten möchte. Das geht mit einer „dictionary comprehension“.

Edit:

Code: Alles auswählen

#!/usr/bin/env python3
from collections import Counter
from random import randrange

LENGTH = 200


def main():
    measurements = [randrange(0, 50) for _ in range(LENGTH)]
    occurrences = Counter(measurements)
    result = {key: value for key, value in occurrences.items() if value <= 2}
    print(result)


if __name__ == '__main__':
    main()
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

@__blackjack__: `measurements.count([ i ])` war noch ein Überbleibsel vom vorherigen fehlgeschlagenen Versuch. Danke für den Code.

`collections.Counter` und `collections.defaultdict` kannte ich noch gar nicht. Schön, dass du sie erwähnt hast.
Meinst du mit ”factory” eine Methode die Key/Value-Einträge im `defaultdict` erstellt?

Die Erstellung einer Kopie war nur die erstbeste Lösung, die mir eingefallen ist, um einen "RuntimeError: dictionary changed size during iteration" zu beheben, weil Einträge aus der Liste, über die die for-Schleife iteriert hat, innerhalb der for-Schleife gelöscht wurden. Eine „dictionary comprehension“ ist da schon besser. Die Bedingung in der „dictionary comprehension“ müsste allerdings `value >= 3` sein, damit sie wie gewünscht funktioniert. :wink:

PS: Wie escaped man eigentlich BBCode bei phpBB?

Gruß
Atalanttore
Benutzeravatar
__blackjack__
User
Beiträge: 14044
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Atalanttore: Eine „factory function“ oder „factory method“ ist eine Funktion/Methode die zum Erzeugen von Objekten da ist. Die Dokumentation von `defaultdict` verwendet den Begriff und das Argument heisst `default_factory`. Der Begriff wird allgemein wesentlich weiter gefasst als er im Entwurfsmuster „Fabrikmethode“ aus dem „GoF“-Buch verstanden wird. Und die Funktion erstellt bei `defaultdict` nur den Wert und nicht den Schlüssel.

Man kann BBCode im vollständigen Beitragseditor komplett abschalten. BBCode selber bietet soweit ich das sehe keine Möglichkeit zum escapen von BBCode, aber man kann sich mit Unicode-Zeichen wie dem „zero width joiner“ behelfen um so etwas wie [‌i] oder [‌b] zu entwerten, damit der Text nicht kursiv oder fett gesetzt wird.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

@__blackjack__: Vom Entwurfsmuster „Fabrikmethode“ gibt es anscheinend viele (kompliziertere) Varianten.
Ist eine einfache Funktion, die Objekte mit unterschiedlichen Parametern instanziiert und zu einer Liste hinzufügt, auch bereits eine „Fabrikfunktion“?

[‍b]Danke[/b] für den Tipp mit „zero width joiner“.

Gruß
Atalanttore
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die Abgrenzung ist da schwierig. Grundsätzlich ist ja jeder Rückgabewert fabriziert worden. Auch ein einfacher int. Das Kriterium ist eher, ob ein komplexes Objekt erzeugt wurde, an das man sonst nicht kommt. In Python ist das fast nicht zu vermeiden, aber zb in Java oder C++ kann man durchaus verbieten, das der Benutzer ein Objekt selbst erzeugt. Da ist die Unterscheidung dann relevanter.

Klassiker sind zb DB Connection Objekte, deren konkreter Typ nicht erzeugt wird, sondern die einer Schnittstelle gehorchen (in Python DB API 2.0) und deren konkrete Instanz per URI Protokoll vorgegeben wird. Sqlalchemy macht sowas genauso, wie auch JDBC.
Benutzeravatar
__blackjack__
User
Beiträge: 14044
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Atalanttore: So an sich ist eine Funktion die eine Liste mit Objekten mit unterschiedlichen Parametern erstellt, keine Fabrikfunktion. Wenn man diese Funktion als Argument für `defaultdict` verwendet, dann schon, denn da ist ja alles eine Fabrik was man da als Argument übergibt.

Ich denke der entscheidende Punkt hier ist das etwas zum Erzeugen von Objekten die bestimmte Bedingungen erfüllen übergeben wurde.

Funktionen und Methoden die an sich schon als Fabrikfunktionen bezeichnet werden können, sind Funktionen und Methoden die als ”(alternative) Konstruktoren” konzipiert sind. Und in Python im Grunde auch Klassen, denn wenn man eine Klasse aufruft ist das ja um ein Objekt zu erzeugen. Das ist beispielsweise in Java anders weil Konstruktoren etwas anders sind als normale Methoden, weil man die nicht einfach austauschen kann wegen dem ``new``-Operator.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Antworten