Remember, groupby in itself, is pretty lame. The strength of itertools.groupby
is the key. For this particular problem, you need to create an appropriate key with memory (stateless key will not work here).
Implementation
class Key(object):
def __init__(self, diff):
self.diff, self.flag, self.prev = diff, [0,1], None
def __call__(self, elem):
if self.prev and abs(self.prev - elem) > self.diff:
self.flag = self.flag[::-1]
self.prev= elem
return self.flag[0]
Object
[list(g) for k, g in groupby(my_list, key = Key(2))]
[[0, 1, 2, 3, 5, 6], [10, 11], [15, 16, 18, 19, 20]]
How it Works
Every time, a new sub-list needs to be created (curr - prev > threshold
), you toggle a flag. There are different ways to toggle a flag
flag = 1; flag *= -1
flag = [0, 1 ]; flag = flag[::-1]
flag = 0; flag = 0 if flag else 1
Choose what ever your heart contends
So this generates an accompanying key along with your list
[0, 1, 2, 3, 5, 6, 10, 11, 15, 16, 18, 19, 20]
[0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0 , 0]
<------> <------>
Toggle flag Toggle flag
0 -> 1, as 1 -> 0, as
10 - 6 > 2 15 - 11 > 2
Now as itertools.groupby
, groups consecutive elements with same key, all elements with keys having consecutive 0
s or 1
s are grouped together
[0, 1, 2, 3, 5, 6, 10, 11, 15, 16, 18, 19, 20]
[0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0 , 0]
[0, 1, 2, 3, 5, 6], [10, 11], [15, 16, 18, 19, 20]
[0, 0, 0, 0, 0, 0], [1, 1], [0, 0, 0, 0 , 0]
And your final result would be
[0, 1, 2, 3, 5, 6], [10, 11], [15, 16, 18, 19, 20]