Zahlensequenzen zu 'Kurven' gruppieren

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
nezzcarth
User
Beiträge: 1793
Registriert: Samstag 16. April 2011, 12:47

Hallo :)

als ich mich eigentlich mie einer anderen Fragestellung befasst habe, bin ich zu folgendem Problem gekommen: ich habe eine Zahlensequenz die ich in steigend-fallende (oder gleichbleibende)
Subsequenzen unterteilen will. Ein Beispiel:

Code: Alles auswählen

[1, 3, 2, 7, 9, 2, 2, 0, 6, 4, 6]
=>
[[1, 3, 2], [7, 9, 2, 2, 0], [6, 4], [6]]
Ein Kumpel von mir hatte mir dafür eine rekursive Lösung in Haskell gezeigt, die wir zusammen nach Python übersetzt haben. Die ist recht übersichtlich, allerdings ist das mit Rekursionen in Python ja so 'ne Sache...

Daher habe ich folgendes versucht (Python 3.x) :

Code: Alles auswählen

def iter_mountains(l):
    result = [l[0]]
    complete = False
    for i, j in zip(l, l[1:]):
        if (j >= i) and not complete:
            result.append(j)
        elif (j <= i):
            result.append(j)
            complete = True
        elif (j >= i) and complete:
            yield result
            result = [j]
            complete = False
    yield result
So richtig schick finde ich das allerdings nicht. Hat vielleicht jemand eine Idee,
ob/wie man das eleganter formulieren könnte?

Danke für jede Antwort :)
Zuletzt geändert von nezzcarth am Mittwoch 24. Oktober 2012, 11:42, insgesamt 1-mal geändert.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Der Code ist doch so in Ordnung. Man sieht auf Anhieb was passiert, was will man mehr? Man könnte wahrscheinlich noch ein wenig mit itertools.groupby drehen, auf Grund des benötigten Status wird die Lösung nicht unbedingt lesbarer als die jetzige Version. Eine Schwachstelle in deinem Code sind allerdings leere Listen, da kommst du über die erste Zeile nicht hinaus.
Das Leben ist wie ein Tennisball.
Benutzeravatar
pillmuncher
User
Beiträge: 1532
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Ich mag itertools:

Code: Alles auswählen

from itertools import izip, tee, chain
from operator import le as up, ge as down


def pairwise(iterable):
    a, b = tee(iterable)
    return izip(a, chain(b, [next(b, None)]))


def mountains(iterable):

    def slope(orientation, neighbors=pairwise(iterable)):
        for left, right in neighbors:
            yield left
            if not orientation(left, right):
                break

    while True:
        mountain = list(chain(slope(up), slope(down)))
        if not mountain:
            break
        yield mountain


xs = [1, 3, 2, 7, 9, 2, 2, 0, 6, 4, 6]
ys = [[1, 3, 2], [7, 9, 2, 2, 0], [6, 4], [6]]
assert ys == list(mountains(xs))
In specifications, Murphy's Law supersedes Ohm's.
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo nezzcarth,

wie EyDu schon geschrieben hat, funktioniert die Funktion für leere Listen nicht.
Das läßt sich aber leicht durch

Code: Alles auswählen

result=l[:1]
in der ersten Zeile lösen.
Die dritte if-Abfrage wird immer erfüllt, falls die ersten beiden nicht zutreffen und sollte
deshalb auch als else-Block geschrieben werden.

Hier noch eine Lösung, die Liste direkt indiziert und nicht erst noch
eine result-Liste Elementweise erzeugt:

Code: Alles auswählen

def iter_mountains(l):
    i = m = 0
    k = -1
    for n,j in enumerate(l):
        if j>i and i<=k:
            yield l[m:n]
            m = n
        k,i = i,j
    yield l[m:]
Grüße
Sirius
nezzcarth
User
Beiträge: 1793
Registriert: Samstag 16. April 2011, 12:47

Danke euchen Dreien für die Antworten.
An die leeren Listen habe ich gar nicht gedacht...

@EyDu: An Groupby hatte ich auch gedacht, hab das aber nicht so recht hinbekommen. Werd's aber noch mal versuchen ;)

@pillmuncher: Ich glaube so 'ne ähnliche Lösung hätte ich bekommen, wenn meinem Kumpel nicht rekursives in Haskell eingefällen wäre ;) Gefällt mir sehr gut, allerdings wäre ich darauf selbst vermutlich nicht gekommen :(

@Sirius3: Deine Variante finde ich etwas schwieriger zu lesen, und ich hantiere auch nicht so gerne mit Indices rum, weil ich da schnell durcheinander komme. Allerdings hat sie natürlich neben der gesparten Liste den Vorteil, dass sie etwas kürzer ist.
Antworten