Seite 1 von 1

Zahlensequenzen zu 'Kurven' gruppieren

Verfasst: Dienstag 23. Oktober 2012, 14:53
von nezzcarth
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 :)

Re: Zahlensequenzen zu 'Kurven' gruppieren

Verfasst: Dienstag 23. Oktober 2012, 15:18
von EyDu
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.

Re: Zahlensequenzen zu 'Kurven' gruppieren

Verfasst: Dienstag 23. Oktober 2012, 16:59
von pillmuncher
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))

Re: Zahlensequenzen zu 'Kurven' gruppieren

Verfasst: Dienstag 23. Oktober 2012, 21:18
von Sirius3
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

Re: Zahlensequenzen zu 'Kurven' gruppieren

Verfasst: Mittwoch 24. Oktober 2012, 15:14
von nezzcarth
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.