简体   繁体   中英

Better way to split list of integers based on values and rules

The goal is to split a list of integers based on each element's neighbors, based on these rules:

  • (the current/focal value is smaller than or equals to the previous) and (the current value is equals to the next), ie prev_value >= focal_value == next_value

  • (the current value is smaller than the previous) and (the current value is smaller than the next), ie prev_value > focal_value < next_value

To illustrate, given the x produce y :

x = (1, 4, 2, 1, 4, 2, 4, 1, 4, 1, 4, 4, 3)
y = [[1, 4, 2], [1, 4], [2, 4], [1, 4], [1, 4, 4, 3]]
assert func(x) == y

I've tried:

def per_window(sequence, n=1):
    """
    From http://stackoverflow.com/q/42220614/610569
        >>> list(per_window([1,2,3,4], n=2))
        [(1, 2), (2, 3), (3, 4)]
        >>> list(per_window([1,2,3,4], n=3))
        [(1, 2, 3), (2, 3, 4)]
    """
    start, stop = 0, n
    seq = list(sequence)
    while stop <= len(seq):
        yield tuple(seq[start:stop])
        start += 1
        stop += 1


def func(x):
    result = []
    sub_result = [x[0]]
    for prev_value, focal_value, next_value in per_window(x, 3):
        # These if and elif cases trigger syllable break.
        if prev_value >= focal_value == next_value:
            sub_result.append(focal_value)
            result.append(sub_result)
            sub_result = []
        elif prev_value > focal_value < next_value:
            result.append(sub_result)
            sub_result = []
            sub_result.append(focal_value)
        else: # no  break
            sub_result.append(focal_value)
    sub_result.append(next_value)
    result.append(sub_result)
    return result


x = (1, 4, 2, 1, 4, 2, 4, 1, 4, 1, 4, 4, 3)
y = [[1, 4, 2], [1, 4], [2, 4], [1, 4], [1, 4, 4, 3]]

assert func(x) == y

But my questions are:

  • If we look at the if and elif "cases" carefully, it looks like the the first if will never be captured since the second one will arrive first. Is that right? What are examples where the first if cases will kick in?

  • Is there a better way to achieve the same goal of splitting the sublist based on the rules?

  • The last two appends needs to exist outside the loop of the per_window , what are these stranglers call? Is there a way to loop without doing so?

  1. With your example, the first if is never triggered. But it will be with this example data:

     x = (5 ,4, 4, 2) y = [[5, 4], [4, 2]]
  2. Better is rather subjective. But it is possible to reach the same goal without using windows, simply by shifting values

    def func2(x): x = iter(x) try: prev_value = next(x) focal_value = next(x) except StopIteration: return [list(x)] sub_result = [prev_value] result = [sub_result] for next_value in x: if prev_value >= focal_value == next_value: sub_result.append(focal_value) sub_result = [] result.append(sub_result) elif prev_value > focal_value < next_value: sub_result = [focal_value] result.append(sub_result) else: sub_result.append(focal_value) prev_value, focal_value = focal_value, next_value sub_result.append(focal_value) return result

    timeit says that it is more that twice faster

  3. As soon as you hold the last value in the loop, you will have do add special processing for it after the loop. But my code shows that it is possible to append the sub_result list inside the loop.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM