Taek Hyung Kim
Taek Hyung Kim

Reputation: 41

How can I split the Python list and make a new lists in ascending order?

In the Python If there are

[1,2,3,4,1,2,3,1,2,1] 

lists, I want to split the list when the size is reduced like this

[1,2,3,4], [1,2,3], [1,2], [1]

How do I code it?

Upvotes: 4

Views: 636

Answers (4)

Scott Boston
Scott Boston

Reputation: 153470

You can use Pandas to do this in three lines:

import pandas as pd
s = pd.Series([1,2,3,4,1,2,3,1,2,1])
s.groupby(s.diff().lt(0).cumsum()).apply(list).tolist()

Output:

[[1, 2, 3, 4], [1, 2, 3], [1, 2], [1]]

Details how it works:

First create a pandas series from the list, then use the diff method in pd.Series to get the difference from the previous value:

s.diff()

0    NaN
1    1.0
2    1.0
3    1.0
4   -3.0
5    1.0
6    1.0
7   -2.0
8    1.0
9   -1.0
dtype: float64

The negative values are indicate the start of a new "sub" list. So, we use lt(0) to mark those records where a new "sub" list should start.

s.diff().lt(0)

0    False
1    False
2    False
3    False
4     True
5    False
6    False
7     True
8    False
9     True
dtype: bool

Next, we are going to use cumsum to create a grouping term. cumsum will only increment when True, so all falses that are next to each other get the same value, then True increments and next group of falses get that new value, until the next True.

s.diff().lt(0).cumsum()

0    0
1    0
2    0
3    0
4    1
5    1
6    1
7    2
8    2
9    3
dtype: int32

Now, we can use groupby with apply to create a new series with these sublist as rows. We are grouping on that newly create grouping term from above and apply the python list to those values in a that group, thus creating the "sub" list.

s.groupby(s.diff().lt(0).cumsum()).apply(list)

0    [1, 2, 3, 4]
1       [1, 2, 3]
2          [1, 2]
3             [1]
dtype: object

Lastly, we apply the tolist method on the series to return the series as a list.

s.groupby(s.diff().lt(0).cumsum()).apply(list).tolist()

Final Output:

[[1, 2, 3, 4], [1, 2, 3], [1, 2], [1]]

Upvotes: 11

Mad Physicist
Mad Physicist

Reputation: 114360

Just for fun, I wanted to see if you could rework the code given in the docs as a sample implementation of itertools.groupby to suit your needs in a general way. The result is a generator whose elements are sub-generators representing your sub-lists. The determination when to split is done by a user-defined function of two variables that accepts each successive pair of neighboring elements and returns True when they are in different groups:

from collections import deque

class splitby:
    # [''.join(s) for s in splitby('AAAABBBCCDAABBB', operator.eq)] --> ['AAAA', 'BBB', 'CC', 'D', 'AA', 'BBB']
    def __init__(self, iterable, splitter):
        self.splitfunc = splitter
        self.it = iter(iterable)
        self.segment = None
    def __iter__(self):
        return self
    def __next__(self):
        if self.segment:
            deque(self.segment, maxlen=0)
            if self.segment is None:
                raise StopIteration
        else:
            self.curvalue = next(self.it)
        self.segment = self._splitter()
        return self.segment
    def _splitter(self):
        split = False
        while not split:
            yield self.curvalue
            prev = self.curvalue
            try:
                self.curvalue = next(self.it)
            except StopIteration:
                self.segment = None
                return
            split = self.splitfunc(prev, self.curvalue)

The whole thing can be applied to your input list with a splitter function of operator.gt or int.__gt__ if your list will only ever contain ints. A suitable wrapping in list will not only properly consume the elements, but will also make the output match your question:

from operator import gt

x = [1, 2, 3, 4, 1, 2, 3, 1, 2, 1]
[list(s) for s in splitby(x, gt)]

The result is:

[[1, 2, 3, 4], [1, 2, 3], [1, 2], [1]]

Here is an IDEOne link: https://ideone.com/UW483U

TL;DR

This is massive overkill for most situations, so don't do it this way. I was just having some fun, but the code here does technically solve your problem. If you put the class into your library somewhere, the actual usage is a one-liner.

Upvotes: 2

warl0ck
warl0ck

Reputation: 3464

If you are looking to split the list when the next number is less than previous one than this might help:

arr = [1,2,3,4,1,2,3,1,2,1]
b = []
start = 0
for i in range(len(arr)):
  if(arr[i] < arr[i-1]):
    b.append(arr[start:i])
    start = i
b.append(arr[start:])
print(b)

Output: [[1, 2, 3, 4], [1, 2, 3], [1, 2], [1]]

Hope this helps.

Upvotes: 2

Vivek Kalyanarangan
Vivek Kalyanarangan

Reputation: 9081

This might be the algorithm you are looking for -

a=[1,2,3,4,1,2,3,1,2,1]
b=[]
c=[]
for i in range(len(a)-1):
    b.append(a[i])
    if a[i] > a[i+1]:
        c.append(b)
        b=[]
print(c)

It outputs a list of sorted lists -

[[1, 2, 3, 4], [1, 2, 3], [1, 2]]

Let me know if that helps.

Upvotes: 2

Related Questions