Gleiche Zahlen zählen und Anzahl ausgeben
Hallo an alle!
Ich bin sowohl hier als auch in python Neuling. Und schon gibt's die ersten Probleme:
Ich möchte jeweils die Anzahl aufeinanderfolgender Einsen in einer liste/array mit 20500 Nullen und Einsen in einer weiteren Liste/array ausgeben.
Beispiel:
list=(0,0,0,0,1,1,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,etc.)
Ausgabe:
list=(2,4,7,1,etc.)
Vielen dank für die Hilfe.
fkh
Ich bin sowohl hier als auch in python Neuling. Und schon gibt's die ersten Probleme:
Ich möchte jeweils die Anzahl aufeinanderfolgender Einsen in einer liste/array mit 20500 Nullen und Einsen in einer weiteren Liste/array ausgeben.
Beispiel:
list=(0,0,0,0,1,1,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,etc.)
Ausgabe:
list=(2,4,7,1,etc.)
Vielen dank für die Hilfe.
fkh
@fkh: Wie sieht denn Dein bisheriger Ansatz aus? Wie würdest Du das Vorgehen denn im Detail beschreiben wenn Du jemandem erzählen solltest wie man das macht? *Das* müsstest Du dann ja nur noch in Quelltext umsetzen.
@BlackJack
Nunja das ist mir selber nicht so ganz klar. Ich habe es schon mit einer while schleife und if bedingung probiert. Sowas wie:
Allerdings habe ich da das Problem, dass ich z.b. für die Sequenz (..,1,1,1,1,...) nicht (...,4,...) erhalte sondern (...1,2,3,4,...). Um das zu umgehen bin ich bis jetzt soweit:
Ich hoffe mein Skript ist einigermaßen verständlich und die Problemstellung klar geworden.
Für weitere Hilfe oder eine einfachere (schnellere) Schleife wär ich sehr dankbar.
Nunja das ist mir selber nicht so ganz klar. Ich habe es schon mit einer while schleife und if bedingung probiert. Sowas wie:
Code: Alles auswählen
p = []
l_max = 0
for n in range(20454)
if time_series_0[n] !=0: #time_series_0 ist hier der array mit 0 und 1 einträgen
l_max = l_max+1
else:
l_max = 0
p.append(l_max)
Code: Alles auswählen
ind_1 = []
lst = list(time_series_0) # time_series_0 ist mein Vektor mit den 0 und 1 Einträgen, der wandele ich hier in eine Liste um, da ich lieber mit Listen arbeite
n = lst.count(1)
print "Anzahl 1er in Zeitreihe:", n
for i in range(n): # hier schreibe ich die Indizes der Stelle in der Liste (lst), welche eine 1 enthalten in eine neue liste (ind_1) und lösche den 1 Eintrag in der Liste (lst)
ind = lst.index(1) # so wie ich mir das vorstelle, sollten jetzt direkt aufeinanderfolgende 1 Einträge in lst den gleichen Index in ind_1 haben.
ind_1.append(ind)
del lst[ind]
p =[]
for t in range(len(ind_1)-1):
temp = cmp(ind_1[t],ind_1[t+1]) # hier vergleiche ich aufeinanderfolgende Indizes miteinander, falls unterschiedlich schreibe ich in die neue Liste p eine 1
if temp != 0:
p.append(1)
if temp == 0: # falls die aufeinanderfolgenden Indizes gleich sind, dann soll hier die Anzahl der gleichen Indizes in die Liste p eingetragen werden
temp2 = ind_1[t+1]
temp3 = ind_1.count(temp2)
print "Anzahl der gleichen indizes:", temp3
if temp3 < 3: # bei Anzahl der gleichen Indizes kleiner als 3 kann ich einfach die Anzahl 2 in die Liste schreiben
p.append(temp3)
elif temp3 > 2: # wenn die Anzahl 3 oder größer ist, habe ich wieder das Problem der Wiederholung: bei z.b. 5 gleichen aufeinanderfolgenden Indizes habe ich
pass # dann (..5, 5, 5, 5..) in meiner Liste p hinzugefügt anstatt nur einer 5, deswegen nur die pass anweisung
print p
Für weitere Hilfe oder eine einfachere (schnellere) Schleife wär ich sehr dankbar.
@fkh: Das ist alles ein wenig kompliziert gemacht. Wie würdest Du das denn von Hand machen? Du kommst ja selbst offensichtlich auf das richtige Ergebnis. Das musst Du beschreiben — in Worten — und diese Beschreibung dann immer detaillierter machen, bis sich die einzelnen Schritte in Quelltext ausdrücken lassen. Wenn Du diese Reihe von 0en und 1en auf einem Blatt Papier hättest und die 1en zählen solltest, dann ist Dir doch wahrscheinlich egal an welchem Index die 0en und 1en stehen. Du fängst doch einfach von vorne an die Ziffern durch zu gehen. Und dann musst Du nur noch umschreiben wann Du jeweils anfängst Ziffern zu zählen und wann Du mit einer Reihe von 1en fertig bist und eine Zahl in der Ergebnisliste notieren musst.
Apropos Index: Das Muster ``for i in xrange(len(sequence)):`` um dann `i` nur zu verwenden um auf Elemente von `sequence` zuzugreifen ist „unpythonisch” weil man stattdessen in der Schleife auch *direkt* über die Elemente von `sequence` iterieren kann.
Apropos Index: Das Muster ``for i in xrange(len(sequence)):`` um dann `i` nur zu verwenden um auf Elemente von `sequence` zuzugreifen ist „unpythonisch” weil man stattdessen in der Schleife auch *direkt* über die Elemente von `sequence` iterieren kann.
list ist kein guter Name für einen Bezeichner, da du dadurch das eingebaute list überschreibst.fkh hat geschrieben:Ich möchte jeweils die Anzahl aufeinanderfolgender Einsen in einer liste/array mit 20500 Nullen und Einsen in einer weiteren Liste/array ausgeben.
Beispiel:
list=(0,0,0,0,1,1,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,etc.)
Das Problem als solches würde ich mit itertools.groupby lösen. Man kann den Beispielcode als Basis nehmen und landet dann bei einem Dreizeiler.
Das ist einer der Fälle wo man sich entscheiden kann ob ein Anfänger mehr lernt, wenn er so etwas mal selbst implementiert, also das Vorgehen „von Hand” als Algorithmus formuliert, oder vorgefertigte Bausteine zusammensetzt. Einen Einzeiler mit `groupby()`, Generatorausdruck, und „list comprehension” hatte ich gestern auch schon gebastelt, aber ich sehe nicht wie man da als Anfänger selber drauf kommt.
Mach dir den Ablauf klar:
- Gehe Zahl für Zahl durch
- Beginne zu zählen, sobald eine Eins auftaucht
- Zähler wird dabei jeweils um eins erhöht
- Folgt eine Null, kommt der Zählerstand in die Ergebnisliste
- Zähler wird anschließend zurückgesetzt
- Wenn über alle Zahlen iteriert wurde, wird die Ergebnisliste ausgegeben
Vorbedingungen: Eine leere Ergebnisliste und ein Zählstand von Null.
Du kannst hier mit einer simplen Fallunterscheidung für jeden Iterationsschritt arbeiten.
- Gehe Zahl für Zahl durch
- Beginne zu zählen, sobald eine Eins auftaucht
- Zähler wird dabei jeweils um eins erhöht
- Folgt eine Null, kommt der Zählerstand in die Ergebnisliste
- Zähler wird anschließend zurückgesetzt
- Wenn über alle Zahlen iteriert wurde, wird die Ergebnisliste ausgegeben
Vorbedingungen: Eine leere Ergebnisliste und ein Zählstand von Null.
Du kannst hier mit einer simplen Fallunterscheidung für jeden Iterationsschritt arbeiten.
Ergänzung: Auf Spezialfälle und Randbedingungen achten. Zum Beispiel leere Liste als Eingabe und 0 oder 1 als letztes Element in der Eingabe.
Hallo allerseits,
Erstmal danke für die vielen Tipps. Nach einer Nacht darüber schlafen, habe ich jetzt auch meinen Denkfehler gefunden. Der Wert des counters darf erst in die Liste, wenn wieder eine 0 vorkommt, also erst in der else Bedingung. Ich würde es jetzt folgendermaßen lösen:
Danke für die vielen Antworten!
Erstmal danke für die vielen Tipps. Nach einer Nacht darüber schlafen, habe ich jetzt auch meinen Denkfehler gefunden. Der Wert des counters darf erst in die Liste, wenn wieder eine 0 vorkommt, also erst in der else Bedingung. Ich würde es jetzt folgendermaßen lösen:
Code: Alles auswählen
p = []
l_max = 0
for n in range(len(time_series_0)):
if time_series_0[n] != 0:
l_max = l_max +1
elif time_series_0[n] == 0:
p.append(l_max)
l_max = 0
p = scipy.array(p)
p = filter(None,p)
Japp, meine Lösung von heute morgen war ganz ähnlich:
Allerdings beachtet dies noch nicht alle durch BlackJack eingeworfenen Sonderfälle/Randbedingungen.
Die `itertools.count()`-Variante wäre übrigens:
Code: Alles auswählen
def count_numbers(numbers):
results = []
counter = 0
for number in numbers:
if number == 1:
counter += 1
elif (number == 0) and counter:
results.append(counter)
counter = 0
return results
numbers = [0,0,0,0,1,1,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0]
print count_numbers(numbers)
Die `itertools.count()`-Variante wäre übrigens:
Code: Alles auswählen
[len(list(group)) for (key, group) in itertools.groupby(numbers) if key == 1]
@snafu:
Vermeidet die überflüssige Liste.
Code: Alles auswählen
[sum(1 for _ in group) for key, group in groupby(numbers) if key == 1]
@lunar:vermeidet die überflüssige generator expression.
Code: Alles auswählen
[sum(group) for key, group in groupby(numbers) if key == 1]
@fkh & snafu: Beide Lösungen haben das gleiche Problem wenn die Einabe mit einer 1 endet.
Code: Alles auswählen
#!/usr/bin/env python
# coding: iso-8859-1
numbers = (0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0)
counts = []
startvalue = -1
tocheck = startvalue
count = 0
for i in numbers:
if i == tocheck:
count +=1
else:
if tocheck != startvalue:
counts.append(count)
tocheck = i
count = 1
for i in counts:
print i
@problembär: Das löst aber nicht die Aufgabe. Es sollen nicht alle Läufe von gleichen Zahlen ermittelt werden, sondern nur die von den 1en. Selbst wenn Du damit alle Läufe zählen möchtest, hat auch diese Lösung das Problem, dass der letzte Wert des Ergebnisses fehlt. Die Ausgabe endet mit einer 1, aber sie müsste ja wegen den zwei letzten 0en mit einer 2 enden.
Das meinte ich eigentlich auch mit "(...) beachtet noch nicht die Einwürfe von BlackJack".
Es hat sich also gezeigt, dass mein Ablauf ungenau definiert war. Als Mensch würde ich ein Ergebnis unter Umständen auch dann aufschreiben, wenn keine Zahlen mehr übrig sind. Damit ich es aufschreibe, muss das Ergebnis grundsätzlich größer als Null sein.
Um in Python herauszufinden, ob noch weitere Iterationsschritte nötig sind, fallen mir diverse Möglichkeiten ein:
1. Elemente mittels `.pop()` abfragen und möglichen `IndexError` behandeln. `.pop()` ist allerdings auf Listen beschränkt.
2a. Weiteren Iterator einführen, der quasi einen Schritt voraus ist und mittels `next()` prüft.
2b. Lediglich *einen* Iterator benutzen, aber `for` durch `while` ersetzen und auch hier mit `next()` arbeiten.
3. Die Schleife durchlaufen und am Ende prüfen, ob Zählstand > 0 ist. Dann genau so verfahren, wie nach einem "Zahlen-Switch". Bedeutet sozusagen Copy&Paste im Kleinformat oder die Einführung einer Hilfsfunktion.
4. Die Länge der Zahlenliste merken und in jedem Schleifendurchlauf dekrementieren.
Ich habe mich dann für die letzte Möglichkeit entschieden und die Funktion gleich auch etwas generischer gestaltet:
Beachtet die Einsen am Ende.
Es hat sich also gezeigt, dass mein Ablauf ungenau definiert war. Als Mensch würde ich ein Ergebnis unter Umständen auch dann aufschreiben, wenn keine Zahlen mehr übrig sind. Damit ich es aufschreibe, muss das Ergebnis grundsätzlich größer als Null sein.
Um in Python herauszufinden, ob noch weitere Iterationsschritte nötig sind, fallen mir diverse Möglichkeiten ein:
1. Elemente mittels `.pop()` abfragen und möglichen `IndexError` behandeln. `.pop()` ist allerdings auf Listen beschränkt.
2a. Weiteren Iterator einführen, der quasi einen Schritt voraus ist und mittels `next()` prüft.
2b. Lediglich *einen* Iterator benutzen, aber `for` durch `while` ersetzen und auch hier mit `next()` arbeiten.
3. Die Schleife durchlaufen und am Ende prüfen, ob Zählstand > 0 ist. Dann genau so verfahren, wie nach einem "Zahlen-Switch". Bedeutet sozusagen Copy&Paste im Kleinformat oder die Einführung einer Hilfsfunktion.
4. Die Länge der Zahlenliste merken und in jedem Schleifendurchlauf dekrementieren.
Ich habe mich dann für die letzte Möglichkeit entschieden und die Funktion gleich auch etwas generischer gestaltet:
Code: Alles auswählen
def count_occurrences(iterable, keyname):
remaining = len(iterable)
results = []
counter = 0
for elem in iterable:
remaining -= 1
if elem == keyname:
counter += 1
if counter and (elem != keyname or not remaining):
results.append(counter)
counter = 0
return results
numbers = [0,0,0,0,1,1,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,1,1,1]
print count_occurrences(numbers, 1)
Na gut, dann prüft man eben noch, ob "tocheck == 1" ist.BlackJack hat geschrieben:@problembär: Das löst aber nicht die Aufgabe. Es sollen nicht alle Läufe von gleichen Zahlen ermittelt werden, sondern nur die von den 1en.
Stimmt, das soll natürlich nicht sein. Das Problem ist, daß der letzte Wechsel nicht mehr in der Schleife berücksichtigt wird, weil kein weiterer Wechsel mehr folgt (und innerhalb der Schleife nur auf Wechsel der Listenelemente geprüft wird). Dann fügt man eben nach der Schleife noch den letzten Stand von "count" der Ergebnisliste an. Also:BlackJack hat geschrieben:Selbst wenn Du damit alle Läufe zählen möchtest, hat auch diese Lösung das Problem, dass der letzte Wert des Ergebnisses fehlt. Die Ausgabe endet mit einer 1, aber sie müsste ja wegen den zwei letzten 0en mit einer 2 enden.
Code: Alles auswählen
#!/usr/bin/env python
# coding: iso-8859-1
numbers = (0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0)
counts = []
startvalue = -1
tocheck = startvalue
count = 0
for i in numbers:
if i == tocheck:
count +=1
else:
if tocheck != startvalue and tocheck == 1:
counts.append(count)
tocheck = i
count = 1
if tocheck == 1:
counts.append(count)
for i in counts:
print i
Code: Alles auswählen
import itertools
numbers = [0,0,0,0,1,1,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,1,1,1,0,1]
groups = (list(grp) for key, grp in itertools.groupby(numbers) if key == 1)
print [len(list_len) for list_len in groups]
Oder habe ich mal wieder was überlesen?
btw Ergebniss = [2, 4, 7, 1, 3, 1]
€ bzw
Code: Alles auswählen
import itertools
numbers = [0,0,0,0,1,1,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,1,1,1,0,1]
print [len(list(grp)) for key, grp in itertools.groupby(numbers) if key == 1]