Listenlement fortlaufend zählen

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
haeuslermartin
User
Beiträge: 66
Registriert: Sonntag 21. April 2013, 10:12

hallo Experten,
wieder einmal ein kleines Listenproblemchen, Listen faszinieren mich einfach, ich hab folgendes versucht:

Code: Alles auswählen

c=[3,4,2,5,2,6,7,5,2,9]

for i in range (len(c)):
    c.count(2)

3
3
3
3
3
3
3
3
3
3
das Ergebnis soll aber sein:

Code: Alles auswählen

0
0
1
1
2
2
2
2
3
3  


Also die Anzahl der 2en bis zum jeweiligen Index, (der Hintergrund wäre dann, den jeweiligen Index durch diesen Wert zu teilen, um die
Entwicklung des prozentualen Anteiles der Zahl 2 zum jeweiligen Stand der Liste zu bekommen)

für wohlmeinende Antworten ein Dankeschön im voraus,
M
Zuletzt geändert von Hyperion am Mittwoch 11. März 2015, 22:18, insgesamt 1-mal geändert.
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@haeuslermartin: und wo sagst Du, dass Du nur die Liste bis zum Index i haben willst?
BlackJack

@haeuslermartin: Wobei man da auch besser nicht bei jedem Schleifendurchlauf von vorne anfangen sollte die Zweien zu zählen. Man kann die doch während des Durchlaufens selber zählen.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du musst halt mitzählen, wenn eine 2 kommt. Das ist eigentlich ganz einfach zu lösen:
- Initialisiere eine Zählavriable mit 0
- Iteriere über die Liste (also ganz normal)
- Wenn eine "2" kommt, erhöhe den Zähler
- Gib den Zähler aus

Das hättest Du Dir doch auch selber so aufschreiben können. Dieses algorithmische Vorgehen musst Du nun "nur" noch in Python Code formulieren :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

Mal im Lisp-Dialekt Hy:

Code: Alles auswählen

#!/usr/bin/env hy

(defn running-count [what iterable]
  (let [count 0]
    (for [x iterable]
      (if (= x what) (setv count (inc count)))
      (yield count))))

(defmain [&rest args]
  (-> (running-count 2 [3 4 2 5 2 6 7 5 2 9]) (list) (print)))
haeuslermartin
User
Beiträge: 66
Registriert: Sonntag 21. April 2013, 10:12

sorry, bei meiner Erläuterung habe ich irrtümlich geschrieben "den Index durch die Anzahl der 2en zu teilen", -um den Prozentsatz zu erhalten
muss man´s natürlich umgekehrt machen, so ist z.B. beim dritten Listeneintrag die 2 einmal vorhanden, hat also einen prozentualen Anteil bisher
von 1 geteilt durch 3 = 0,33, also 33 Prozent, beim vierten Eintrag ist sie auch nur einmal da, also 1/4 =0,25 (25%,)
beim 5. Eintrag haben wir sie zweimal, also 2/5 = 40%, usw., so dass man sehen kann ob ihr prozentualer Anteil gleich bleibt oder sich verändert.
Desweiteren ist die Länge der Liste unbestimmt, sie erweitert sich ständig durch Einträge, muss also immer wieder neu gezählt werden, oder
habe ich da einen Denkfehler? :? :?:

dabei noch eine Eigenheit:
normal beginnt der Index ja mit 0, für die korrekte Prozentanteilberechnung muss er aber mit 1 beginnen, wie wärs mit:

c= [2,3,4,2,6,2,4,3]

b = len(c)

history = [i for i in range(1,b+1)]

:?:
Zuletzt geändert von haeuslermartin am Donnerstag 12. März 2015, 13:20, insgesamt 1-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Für das Mitzählen der bisher durchlaufenen Elemente kannst Du ``enumerate`` nutzen. Das würde an dem von mir beschriebenen Algorithmus aber nichts ändern.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

Das mit den Prozenten in Io:

Code: Alles auswählen

Number asPercent := method((self * 100) asString(6, 2) .. "%")

List runningPercentageOf := method(what,
    count := 0
    result := List clone
    self foreach(i, value,
        (value == what) ifTrue(count = count + 1)
        result append(count / (i + 1))
    )
)

List with(2, 3, 4, 2, 6, 2, 4, 3) runningPercentageOf(2) foreach(percentage,
    percentage asPercent println
)
:-)
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Mit itertools:

Code: Alles auswählen

    from itertools import accumulate
    from random import randint
    numbers = [randint(0, 9) for _ in range(30)]
    counted = accumulate(1 if m == 2 else 0 for m in numbers)
    for i, (n, c) in enumerate(zip(numbers, counted), start=1):
        print(n, c, '{0:.2%}'.format(c / i))
In specifications, Murphy's Law supersedes Ohm's.
haeuslermartin
User
Beiträge: 66
Registriert: Sonntag 21. April 2013, 10:12

hallo Experten,

zunächst ein Dankeschön für Eure Antworten, es ist das einzige feedback, das ich als Autodidakt bekommen kann, in meinem Umfeld und meiner
Alterklasse gibts da sonst niemand. Ich sehe immer mehr, dass es fast unmöglich ist, alleine nur mit einem Buch das Programmieren zu lernen.
In den Büchern und in den Beiträgen, die man ergoogeln kann, gibts jede Menge Info´s über die ganz grundsätzlichen Sachen, aber wenn ich dann
vor einem praktischen Problem stehe, wie diesem letzten hier, dann stelle ich immer wieder fest, dass mit dem Grundwissen alleine noch recht wenig
anzufangen ist.
Da ich gerade dabei bin, python als erste Programmiersprache zu lernen, kann ich mit einer fremden, (lisp) nichts anfangen, war aber sicher
bestens gemeint.
Die zweite Antwort , lieber pillmuncher, erfordert jetzt Recherchearbeit, da bin ich momentan überfordert, ich muss mich schlau machen, was da importiert wird und was diese Module machen, auch muss ich noch rauskriegen, wo da meine Listeneinträge rein sollen ... aber auf jeden Fall
vielen Dank!

sorry, vielleicht nehme ich mir da immer zuviel vor die Brust, aber andererseits heißt es doch gerade beim Programmieren lernen, learning by doing
ist die beste Herangehensweise ...

:? :K
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Als Anfänger ist es sicher leichter, erst einmal alles Schritt für Schritt zu machen. Das hilft dann auch den Algorithmus zu verstehen. Da Beispiele hilfreich sein können, hier eine anfängerfreundliche Lösung:

Code: Alles auswählen

c = [3,4,2,5,2,6,7,5,2,9]
counter = 0
percentage = 0

for n, item in enumerate(c, start=1):
    if item == 2:
        counter += 1
        percentage = counter / n
    print(n, '{0:.2%}'.format(percentage))
haeuslermartin
User
Beiträge: 66
Registriert: Sonntag 21. April 2013, 10:12

nochmal danke, kbr ich habs probiert und kann es nachvollziehen.
Jetzt würde mich aber interessieren: gibt es denn einen Vorteil in pillmunchers vorgeschlagener Lösung? warum sonst sollte man sowas "schwierig" programmieren, wenn einfach geht, da muss doch wo irgendwo ein Unterschied sein? ist es die Laufzeit? oder die Erweiterungsfähigkeit?
oder einfach, weils für Experten "eleganter", ("fachgerechter") ist? :) :)
M.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Mal mit Beschreibung:

Code: Alles auswählen

from itertools import accumulate
from random import randint
itertools und random sind Module in der Standardbibliothek. Ersteres beinhaltet Funktionen zur Verarbeitung von Abfolgen im weitesten Sinne (das nennt man in Python Iteratoren), zweiteres dient zur Erzeugung von Zufallszahlen und was damit zusammenhängt.

accumulate() ist eine Funktion, die eine laufende Akkumulation von Werten vornimmt. Angenommen die Folge 1, 2, 3, 4, 5, dann erzeugt accumulate() daraus die Folge 1, 3, 6, 10, 15, d.h. (1), (1 + 2), (1 + 2 + 3), (1 + 2 + 3 + 4), (1 + 2 + 3 + 4 + 5).

randint() ist eine Funktion, die eine Zufallszahle (ein Integer) zwischen zwei Zahlen (einschließlich) erzeugt. Das Ergebnis von randint(10, 20) ist also irgendeine Zahl von 10 bis 20.

Code: Alles auswählen

numbers = [randint(0, 9) for _ in range(30)]
Hier verwende ich range(30) um dreißig Zahlen zu erzeugen. An den Zahlen bin ich jedoch gar nicht interessiert, nur daran, dass es dreißig sind. Mein Desinteresse bringe ich dadurch zum Ausdruck, dass ich die Zahlen an _ binde, was ein geläufiges Idiom in Python darstellt. Für jede dieser ignorierten Zahlen rufe ich einmal randint(1, 9) auf und erhalte so dreißig Zufallszahlen im Bereich 1 bis 9. Die Konstruktion mit der for-Schleife in eckigen Klammern nennt man list comprehension.

Code: Alles auswählen

counted = accumulate(1 if m == 2 else 0 for m in numbers)
Für jede der Zahlen teste ich sie gleich zwei ist. Wenn ja, erzeuge ich eine Eins und andernfalls eine Null. Wenn ich über der so entstehenden Folge von Einsen und Nullen mit accumulate() die laufende Summe bilde, wird für jede gefundene Zwei die Summe um eins erhöht.

Code: Alles auswählen

for i, (n, c) in enumerate(zip(numbers, counted), start=1):
Mit zip() kann man aus mehreren Folgen eine machen, so dass das neue erste Element ein Tupel der ersten Elemente der ursprünglichen Folgen ist (die Reihenfolge der Elemente bleibt dabei dieselbe wie die der Ausgangsfolgen). Nehmen wir zB. die Listen [1, 2, 3] und [4, 5, 6], dann ergibt list(zip([1, 2, 3], [4, 5, 6])) die neue Liste [(1, 4), (2, 5), (3, 6)].

enumerate() erzeugt ebenfalls eine Folge von Tupeln. Die bestehen aus dem Index des Elements und dem Element selbst. Angenommen die Liste x = ['Tische', 'Stühle', 'Bierseidel'], dann erzeugt list(enumerate(x)) die Liste [(0, 'Tische'), (1, 'Stühle'), (2, 'Bierseidel')]. Wenn man nicht mit Null beginnen möchte, kann man einen anderen Startwert angeben, im o.s. Fall die Eins.

Code: Alles auswählen

    print(n, c, '{0:.2%}'.format(c / i))
Für Strings gibt es eine Formatsprache für Templates, mit der man angeben kann, wie Werte formatiert werden sollen. Das '{0:.2%}' bedeutet, dass das Argument von .format(c / i), also das Ergebnis der Rechnung (c / i) als Prozentzahl mit zwei Nachkommastellen dargestellt wird, wobei man nichtmal selbst mit 100 Multiplizieren muss, denn das geschieht automatisch. Die Zahl 0.256789 wird also als 25.68% dargestellt.
In specifications, Murphy's Law supersedes Ohm's.
haeuslermartin
User
Beiträge: 66
Registriert: Sonntag 21. April 2013, 10:12

hallo pillmuncher,

sehr herzlichen Dank, da hast Du Dir viel Mühe gemacht mit meiner Sache, und ich habe jetzt für die nächsten Tage jede Menge Stoff zu lernen
und zu verarbeiten, das bringt mich ein gutes Stück weiter. Manches, wie z.B. zip war mir schon bekannt, aber das ganze beginne ich erst
jetzt, -mit Deinen Erklärungen- zu checken.

ja, mit Lehrer wär´s halt um Kilometer effektiver, das Lernen.
Dankeschön nochmal.
M.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Und jetzt vergleiche mal meinen textuellen Ansatz mit der Lösung von kbr ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
haeuslermartin
User
Beiträge: 66
Registriert: Sonntag 21. April 2013, 10:12

hallo lieber kbr,

bin mit Grippe flachgelegen, deswegen die Verzögerung, Dein code
rechnet noch nicht die richtigen Ergebnisse aus:

Code: Alles auswählen

c= [3,4,2,5,2,6,7,5,2,9]

counter = 0
percentage = 0
 
for n, item in enumerate(c, start=1):
    if item == 2:
        counter += 1
        percentage = counter / n
    print(n, '{0:.2%}'.format(percentage))
output:

1 0.00% richtig
2 0.00% richtig
3 33.33% richtig 1/3 = 0,33
4 33.33% falsch 1/4 = 0,25 !!!
5 40.00% richtig 2/5 = 0,40
6 40.00% falsch 2/6 = 0,33 !!!
7 40.00% falsch 2/7 = 0,29 !!!
8 40.00% falsch 2/8 = 0,25 !!!
9 33.33% richtig 3/9 = 0,33
10 33.33% falsch 3/10 = 0,30 !!!

wenn sich n erhöht, "counter item" aber gleich bleibt, nimmt der prozentuale Anteil wieder ab
http://www.python-forum.de/posting.php? ... =1&t=35886#
Zuletzt geändert von Anonymous am Mittwoch 25. März 2015, 15:23, insgesamt 1-mal geändert.
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@haeuslermartin: wenn Du kbrs Programm verstanden hast, sollte es ganz einfach sein, den Fehler zu korrigieren
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

haeuslermartin hat geschrieben:wenn sich n erhöht, "counter item" aber gleich bleibt, nimmt der prozentuale Anteil wieder ab
Tja, da sind dem Fall von n syntaktisch relevanten Leerzeichen wohl knapp 17% zuviel in den Code geraten ...
Antworten