Cranjis
Cranjis

Reputation: 1960

Python group list to sub-lists lists that are monotonic with equal diff between elements

l = [2,4,6,12,14,16,21,27,29,31]

I want to split it to lists, such that each list's elements are a monotonic list with diff of 2 between elements:

new_l = [[2,4,6], [12,14,16],[21], [27,29,31]]

What is the most efficient way to do this?

Upvotes: 1

Views: 152

Answers (2)

Maaddy
Maaddy

Reputation: 628

Update
It is possible to avoid Python loops altogether and only use comprehensions (along with zip) for some efficiency gain. You can do that like the following:

l = [2,4,6,12,14,16,21,27,29,31, 44]
n = len(l)
#Find the splitting points (where the monotonic condition breaks):
splitting_points = [0] + [k for k in range(1, n) if l[k] - l[k - 1] != 2]
if splitting_points[-1] != n:
    splitting_points.append(n)
#Then split the list into intervals having bounds in the splitting_points:
new_l = [l[i: j] for i, j in zip(splitting_points[:-1], splitting_points[1:])]
print(new_l)

This "should" be quite faster than loops (especially for large lists), but I haven't done any benchmarking.

Original
You have to iterate over the initial list l, maintain a current list that has the current monotonic sequence, and whenever the new iterated element breaks the monotonic condition, insert the current list and clear it.
Here's a code that does exactly that:

l = [2,4,6,12,14,16,21,27,29,31]
new_l = []
current_l = [l[0]]                #initially, insert the first element
for k in range(1, len(l)):
    if l[k] - current_l[-1] == 2: #if the monotonic condition is satisfied
        current_l.append(l[k])    #we append the element
    else:
        new_l.append(current_l)   #otherwise, we append the previous list to the answer
        current_l = [l[k]]        #and clear the running sequence
new_l.append(current_l)           #there will always be a last sequence not appended to the answer
print(new_l)

Upvotes: 1

mathfux
mathfux

Reputation: 5949

You could identify indices where to split and then apply np.split like so:

np.split(l, np.flatnonzero(np.diff(l)!=2) + 1)

Output:

[array([2, 4, 6]), array([12, 14, 16]), array([21]), array([27, 29, 31])]

However, playing with arrays of different lenghts is never efficient so that's why np.split is quite slow.

Upvotes: 1

Related Questions