简体   繁体   中英

reverse ascending sequences in a list

Trying to figure out how to reverse multiple ascending sequences in a list.

For instance: input = [1,2,2,3] to output = [2,1,3,2] .

I have used mylist.reverse() but of course it reverses to [3,2,2,1] . Not sure which approach to take?

Example in detail:

So lets say [5, 7, 10, 2, 7, 8, 1, 3] is the input - the output should be [10,7,5,8,7,2,3,1] . In this example the first 3 elements 5,7,10 are in ascending order, 2,7,8 is likewise in ascending order and 1,3 also in ascending order. The function should be able to recognize this pattern and reverse each sequence and return a new list.

All you need is to find all non-descreasing subsequences and reverse them:

In [47]: l = [5, 7, 10, 2, 7, 8, 1, 3]    

In [48]: res = []

In [49]: start_idx = 0

In [50]: for idx in range(max(len(l) - 1, 0)):
    ...:     if l[idx] >= l[idx - 1]:
    ...:         continue
    ...:     step = l[start_idx:idx]
    ...:     step.reverse()
    ...:     res.extend(step)
    ...:     start_idx = idx
    ...:

In [51]: step = l[start_idx:]

In [52]: step.reverse()

In [53]: res.extend(step)

In [54]: print(res)
[10, 7, 5, 8, 7, 2, 3, 1]

For increasing subsequences you need to change if l[idx] >= l[idx - 1] to if l[idx] > l[idx - 1]

There is probably a more elegant way to do this, but one approach would be to use itertools.zip_longest along with enumerate to iterate over sequential element pairs in your list and keep track of each index where the sequence is no longer ascending or the list is exhausted in order to slice, reverse, and extend your output list with the sliced items.

from itertools import zip_longest

d = [5, 7, 10, 2, 7, 8, 1, 3]

results = []
stop = None
for i, (a, b) in enumerate(zip_longest(d, d[1:])):
    if not b or b <= a:
        results.extend(d[i:stop:-1])
        stop = i

print(results)
# [10, 7, 5, 8, 7, 2, 3, 1]

Walk the list making a bigger and bigger window from x to y positions. When you find a place where the next number is not ascending, or reach the end, reverse-slice the window you just covered and add it to the end of an output list:

data = [5, 7, 10, 2, 7, 8, 1, 3]
output = []

x = None
for y in range(len(data)):
  if y == len(data) - 1 or data[y] >= data[y+1]:
    output.extend(data[y:x:-1])
    x = y

print(output)
data = [5, 7, 10, 2, 7, 8, 1, 3,2]
def func(data):
    result =[]
    temp =[]
    data.append(data[-1])
    for i in range(1,len(data)):
        if data[i]>=data[i-1]:
            temp.append(data[i-1])
        else:
            temp.append(data[i-1])
            temp.reverse()
            result.extend(temp)
            temp=[]
    if len(temp)!=0:
        temp.reverse()
        result.extend(temp)
    temp.clear()
    return result

print(func(data))

# output [10, 7, 5, 8, 7, 2, 3, 1, 2] 

You could define a general handy method which returns slices of an array based on condition (predicate).

def slice_when(predicate, iterable):
  i, x, size = 0, 0, len(iterable)
  while i < size-1:
    if predicate(iterable[i], iterable[i+1]):
      yield iterable[x:i+1] 
      x = i + 1
    i += 1
  yield iterable[x:size] 


Now, the slice has to be made when the next element is smaller then the previous, for example:

 array = [5, 7, 10, 2, 7, 8, 1, 3] slices = slice_when(lambda x,y: x > y, array) print(list(slices)) #=> [[5, 7, 10], [2, 7, 8], [1, 3]] 

So you can use it as simple as:

 res = [] for e in slice_when(lambda x,y: x > y, array): res.extend(e[::-1] ) res #=> [10, 7, 5, 8, 7, 2, 3, 1] 

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