hsekol
hsekol

Reputation: 173

make list as nested list with consecutive elements in separate list

I want to separate list of elements into nested list, each sub list having consecutive elements. If an element doesn't have a consecutive element, it should have in single list.

Input:

l1 = [1, 2, 3, 11, 12, 13, 23, 33, 34, 35, 45]
l2 = [11, 12, 13, 22, 23, 24, 33, 34]
l3 = [1, 2, 3, 11, 12, 13, 32, 33, 34, 45]

expected output:

l1 = [[1, 2, 3], [11, 12, 13], [23], [33, 34, 35], [45]]
l2 = [[11, 12, 13], [22, 23, 24], [33, 34]]
l3 = [[1, 2, 3], [11, 12, 13], [32, 33, 34], [45]]

I have tried the code below but it is not giving the expected result, printing an empty list:

def split_into_list(l):

    t = []
    for i in range(len(l) - 1):

        if abs(l[i] - l[i + 1]) == 0:
            t.append(l[i])

        elif abs(l[i] - l[i + 1]) != 0 and abs(l[i - 1] - l[i]) == 0:
            t.append(l[i])
            yield t
            split_into_list(l[i:])
        if i + 1 == len(l):
            t.append(l[i])
            yield t

l = [1, 2, 3, 11, 12, 13, 32, 33, 34, 45]
li = []
li.append(split_into_list(l))

for i in li:
    print(i, list(i))

Upvotes: 2

Views: 540

Answers (4)

Mad Physicist
Mad Physicist

Reputation: 114440

This is something that lends itself well to a numpy solution using diff and split:

def consecutives(x):
    np.split(x, np.flatnonzero(np.diff(x) != 1) + 1)

For example, consecutives(l1) will result in

[array([1, 2, 3]),
 array([11, 12, 13]),
 array([23]),
 array([33, 34, 35]),
 array([45])]

If you need nested lists, you can apply list or ndarray.tolist:

def consecutives(x):
    return [a.tolist() for a in np.split(x, np.flatnonzero(np.diff(x) != 1) + 1)]

Now the result of consecutives(l1) is

[[1, 2, 3], [11, 12, 13], [23], [33, 34, 35], [45]]

Upvotes: 0

SolAeterna
SolAeterna

Reputation: 103

def split_into_list(l):
    t = []
    temp = [l[0]]
    prev = l[0]
    for i in l[1:]:
        if i == prev+1:
            temp.append(i)
        else:
            t.append(temp)
            temp = [i]
        prev = i
    return t

Mind that all solutions so far relie on sorted lists, which you didn't expicitly specify in your question.

Upvotes: 0

smarie
smarie

Reputation: 5226

def split_into_list(l):
    result = [[]]
    for i, elt in enumerate(l[1:]):
        diff = abs(elt - l[i])
        if diff == 1:
            # still the same group
            result[-1].append(elt)
        else:
            # new group
            result.append([elt])
    return result



l = [1,2,3,11,12,13,32,33,34,45]
print(split_into_list(l))

yields

[[2, 3], [11, 12, 13], [32, 33, 34], [45]]

Upvotes: 0

RomanPerekhrest
RomanPerekhrest

Reputation: 92874

Shorter approach with custom split_adjacent function:

def split_adjacent(lst):
    res = [[lst[0]]]    # start/init with the 1st item/number
    for i in range(1, len(lst)):
        if lst[i] - res[-1][-1] > 1:  # compare current and previous item
            res.append([])
        res[-1].append(lst[i])
    return res


l1 = [1, 2, 3, 11, 12, 13, 23, 33, 34, 35, 45]
l2 = [11, 12, 13, 22, 23, 24, 33, 34]
l3 = [1, 2, 3, 11, 12, 13, 32, 33, 34, 45]

print(split_adjacent(l1))
print(split_adjacent(l2))
print(split_adjacent(l3))

Final output:

[[1, 2, 3], [11, 12, 13], [23], [33, 34, 35], [45]]
[[11, 12, 13], [22, 23, 24], [33, 34]]
[[1, 2, 3], [11, 12, 13], [32, 33, 34], [45]]

Upvotes: 2

Related Questions