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
Subclassing Python Dictionary to Override _Setitem_
What Are All the Dtypes That Pandas Recognizes
Python Ignore Certificate Validation Urllib2
How to Get Tweets Older Than a Week (Using Tweepy or Other Python Libraries)
How to Assign the Same Value to Multiple Keys in a Dict Object at Once
Python Insert Numpy Array into SQLite3 Database
Stop Matplotlib Repeating Labels in Legend
Running Multiple Bash Commands with Subprocess
Reading Tar File Contents Without Untarring It, in Python Script
How to Save the Pandas Dataframe/Series Data as a Figure
How to Read a Response from Python Requests
How Dangerous Is Setting Self._Class_ to Something Else
Inline CSV File Editing with Python
Representing and Solving a Maze Given an Image
Detect Tap with Pyaudio from Live Mic