Splitting List Based on Missing Numbers in a Sequence

Splitting list based on missing numbers in a sequence

Python 3 version of the code from the old Python documentation:

>>> # Find runs of consecutive numbers using groupby.  The key to the solution
>>> # is differencing with a range so that consecutive numbers all appear in
>>> # same group.
>>> from itertools import groupby
>>> from operator import itemgetter
>>> data = [ 1, 4,5,6, 10, 15,16,17,18, 22, 25,26,27,28]
>>> for k, g in groupby(enumerate(data), lambda i_x: i_x[0] - i_x[1]):
... print(list(map(itemgetter(1), g)))
...
[1]
[4, 5, 6]
[10]
[15, 16, 17, 18]
[22]
[25, 26, 27, 28]

The groupby function from the itertools module generates a break every time the key function changes its return value. The trick is that the return value is the number in the list minus the position of the element in the list. This difference changes when there is a gap in the numbers.

The itemgetter function is from the operator module, you'll have to import this and the itertools module for this example to work.

Alternatively, as a list comprehension:

>>> [map(itemgetter(1), g) for k, g in groupby(enumerate(seq2), lambda i_x: i_x[0] - i_x[1])]
[[1, 2], [4, 5, 6], [8, 9, 10]]

Splitting list based on difference between consecutive elements

Two lines with list-comprehension:

def split_list(l, n):
index_list = [None] + [i for i in range(1, len(l)) if l[i] - l[i - 1] > n] + [None]
return [l[index_list[j - 1]:index_list[j]] for j in range(1, len(index_list))]

test:

example = [1, 2, 3, 6, 8, 10, 14, 15, 17, 20]
for i in range(2,5):
print(split_list(example, i))

# [[1, 2, 3], [6, 8, 10], [14, 15, 17], [20]]
# [[1, 2, 3, 6, 8, 10], [14, 15, 17, 20]]
# [[1, 2, 3, 6, 8, 10, 14, 15, 17, 20]]

Linq splitting group if there is missing number

See if this works. No for loop, just linq

            List<int> list = new List<int> { 1, 2, 3, 5, 6, 7, 9, 10};
List<int> splitIndex = list.Skip(1).Select((x,i) => new { x = x, i = i}).Where(x => list[x.i] + 1 != x.x).Select(x => x.i).ToList();
//add last index
splitIndex.Add(list.Count - 1);
var results = splitIndex.Select((x,i) => (i == 0) ? list.Take(x + 1).ToList() : list.Skip(splitIndex[i - 1] + 1).Take(splitIndex[i] - splitIndex[i - 1]).ToList()).ToList();

Python splitting a datetime list based on missing days

This works for the given example...

>>> import datetime
>>> date_list = [
... datetime.datetime(2012,1,1,0,0,0),
... datetime.datetime(2012,1,2,0,0,0),
... datetime.datetime(2012,1,4,0,0,0),
... datetime.datetime(2012,1,7,0,0,0),
... datetime.datetime(2012,1,8,0,0,0),
... ]
>>> import itertools
>>> [list(g) for k, g in itertools.groupby(enumerate(date_list), key=lambda (i, x): i-x.day)]
[[(0, datetime.datetime(2012, 1, 1, 0, 0)), (1, datetime.datetime(2012, 1, 2, 0, 0))], [(2, datetime.datetime(2012, 1, 4, 0, 0))], [(3, datetime.datetime(2012, 1, 7, 0, 0)), (4, datetime.datetime(2012, 1, 8, 0, 0))]]

This may be better if you don't want the index...

>>> [[v for i, v in g] for k, g in itertools.groupby(enumerate(date_list), key=lambda (i, x): i-x.day)]
[[datetime.datetime(2012, 1, 1, 0, 0), datetime.datetime(2012, 1, 2, 0, 0)], [datetime.datetime(2012, 1, 4, 0, 0)], [datetime.datetime(2012, 1, 7, 0, 0), datetime.datetime(2012, 1, 8, 0, 0)]]

How to split a sequential integer array, if any sequence is missing

You can just sort your array and iterate them in order. Check if the element minus one is equal to the last element of your 2D array, if true append otherwise append a new array with the element and increase the index of the subarrays:

extension Collection where Element == Int {
func grouped() -> [[Element]] {
let elements = Set(self).sorted()
guard let first = elements.first else { return [] }
var result = [[first]]
var i = 0
for element in elements.dropFirst() {
if element-1 == result[i].last! {
result[i].append(element)
} else {
result.append([element])
i += 1
}
}
return result
}
}

let myArray =  [0,1,2,4,7,8]
let grouped = myArray.grouped() // [[0, 1, 2], [4], [7, 8]]

Splitting a list of integers into sublists given 0 as separator

You could use itertools.groupby in order to group the elements in the list that appear between 0s:

from itertools import groupby
[list(v) for k,v in groupby(l, key = lambda x: x != 0) if k != 0]
# [[6, 6], [5, 4, 5], [4, 6]]

Details

The key argument here key = lambda x: x != 0 is transforming the list so that it is instead grouped by:

[x != 0 for x in l]
# [True, True, False, True, True, True, False, False, True, True]

Note that that groupby groups consecutive values that are equal.
So this key will yield the following values as a result of the groupby:

[list(v) for k,v in groupby(l, key = lambda x: x != 0)]
[[6, 6], [0], [5, 4, 5], [0, 0], [4, 6]]

Now we only have to specify that we want to keep the values if the key is not 0, which can be done by adding if k != 0 at the end of the list comprehension.


Helpful reads:

  • List comprehensions
  • itertools.groupby


Related Topics



Leave a reply



Submit