the zip function is your friend when you need to compare items of a list with their successor or predecessor:
x=[10,11,13,70,71,73,170,171,172,174]
threshold = 50
breaks = [i for i,(a,b) in enumerate(zip(x,x[1:]),1) if b-a>threshold]
groups = [x[s:e] for s,e in zip([0]+breaks,breaks+[None])]
print(groups)
[[10, 11, 13], [70, 71, 73], [170, 171, 172, 174]]
breaks
will contain the index (i
) of elements (b
) that are greater than their predecessor (a
) by more than the treshold
value.
- Using zip() again allows you to pair up these break indexes to form start/end ranges which you can apply to the original list to get your groupings.
Note that i used a fixed threshold to detect a "huge" deviation, but you can use a percentage or any formula/condition of your choice in place of if b-a>threshold
. If the deviation calculation is complex, you will probably want to make a deviates()
function and use it in the list comprehension: if deviates(a,b)
so that it remains intelligible
If zip() and list comprehensions are too advanced, you can do the same thing using a simple for-loop:
def deviates(a,b): # example of a (huge) deviation detection function
return b-a > 50
groups = [] # resulting list of groups
previous = None # track previous number for comparison
for number in x:
if not groups or deviates(previous, number):
groups.append([number]) # 1st item or deviation, add new group
else:
groups[-1].append(number) # approximately adjacent, add to last group
previous = number # remember previous value for next loop