Reputation: 41
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
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]]
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
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
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
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