Seite 1 von 1
Werte in Liste zählen und mehrmals vorgekommene Werte ausgeben
Verfasst: Dienstag 28. Mai 2019, 20:49
von Atalanttore
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
Re: Werte in Liste zählen und mehrmals vorgekommene Werte ausgeben
Verfasst: Dienstag 28. Mai 2019, 21:08
von __blackjack__
@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()
Re: Werte in Liste zählen und mehrmals vorgekommene Werte ausgeben
Verfasst: Mittwoch 29. Mai 2019, 18:51
von Atalanttore
@__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.
PS: Wie escaped man eigentlich BBCode bei phpBB?
Gruß
Atalanttore
Re: Werte in Liste zählen und mehrmals vorgekommene Werte ausgeben
Verfasst: Freitag 31. Mai 2019, 09:06
von __blackjack__
@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.
Re: Werte in Liste zählen und mehrmals vorgekommene Werte ausgeben
Verfasst: Freitag 31. Mai 2019, 20:00
von Atalanttore
@__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
Re: Werte in Liste zählen und mehrmals vorgekommene Werte ausgeben
Verfasst: Freitag 31. Mai 2019, 21:29
von __deets__
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.
Re: Werte in Liste zählen und mehrmals vorgekommene Werte ausgeben
Verfasst: Freitag 31. Mai 2019, 22:05
von __blackjack__
@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.