-1

If I have a list

l = [0, 0, 1, 2, 2, 2, 1, -1, -1, -1, 0]

I hope to obtain three zig-zag, a zig-zag is defined as local maxima (can be a plateau) and minima (can be a valley), as shown below, there are 3 zig zags, A, B, C while A and B overlap in the plateau, B and C overlap in the valley

A = [0, 0, 1, 2, 2, 2]
B = [2, 2, 2, 1, -1, -1, -1]
C = [-1, 0]

enter image description here

tesla1060
  • 2,621
  • 6
  • 31
  • 43
  • 2
    I suspect you need to make this a more specific question. Are you just asking for general algos to do this? Have you tried anything? – doctorlove Aug 13 '13 at 09:56
  • I am wondering if there is any off-the-self Python or R package already does that, or any fast few line algo to do that. – tesla1060 Aug 13 '13 at 09:58
  • This might get you started in R: http://stackoverflow.com/q/6836409/1412059 – Roland Aug 13 '13 at 10:23
  • [`TTR::ZigZag`](https://r-forge.r-project.org/scm/viewvc.php/pkg/R/ZigZag.R?view=markup&revision=163&root=ttr)? – Joshua Ulrich Aug 13 '13 at 11:32
  • hi, @JoshuaUlrich I have tried TTR::ZigZag, but for the time series, I have, it sometimes split the end point at the middle of the plateau. and also, if I am not wrong, it interpolates, it doesnt gives the index of the minima and maxima. – tesla1060 Aug 13 '13 at 12:30
  • Hi @Roland, I saw that too. but the algo has problem, for one thing if I have a list of [0, 0, 1, 2, 2, 2, 3, 3, 3], it will treat [2] as maxima too. – tesla1060 Aug 13 '13 at 12:33
  • By the way your question does not match with the picture, your `C` has only one `-1` value, but in the picture there are many more points with `-1` value. – Antti Haapala -- Слава Україні Aug 14 '13 at 08:09

1 Answers1

1

A solution in general Python, note that the l can be any iterator, and it is scanned only once.

l = [0, 0, 1, 2, 2, 2, 1, -1, -1, -1, 0]

def zigzag(l):
    if not l:
        return []

    last = l[0]

    # the elements in current rise    
    current_rise = []

    # the elements in current drop
    current_drop  = []

    # return value
    zigzags = []

    # iterate over elements
    for i in l:
        # if we are growing...
        if i > last:
            # and the current_drop is longer than
            # current rise, then we just stopped a drop
            if len(current_drop) > len(current_rise):
                zigzags.append(current_drop)

            # in any case, a new drop can start here.
            current_drop = [i]

        else:
            # else just accumulate a current drop
            current_drop.append(i)

        # same for the other direction
        if i < last:
            if len(current_rise) > len(current_drop):
                zigzags.append(current_rise)

            current_rise = [i]

        else:
            current_rise.append(i)

        last = i

    # add the final segment    
    if len(current_rise) > len(current_drop):
        zigzags.append(current_rise)
    else:
        zigzags.append(current_drop)

    return zigzags

print zigzag(l)
# result [[0, 0, 1, 2, 2, 2], [2, 2, 2, 1, -1, -1, -1], [-1, -1, -1, 0]]
  • Hi, it seems this algo will fail if we have `l = [1, 0, 1, 0]`, I think `if len(current_drop) > len(current_rise):` need to be changed to `if len(current_drop) >= len(current_rise) and len(current_drop)>1 and current_drop[0] <> current_drop[-1]:` same for the other `if` – tesla1060 Aug 15 '13 at 09:01