Identify groups of continuous numbers in a list
more_itertools.consecutive_groups
was added in version 4.0.
Demo
import more_itertools as mit
iterable = [2, 3, 4, 5, 12, 13, 14, 15, 16, 17, 20]
[list(group) for group in mit.consecutive_groups(iterable)]
# [[2, 3, 4, 5], [12, 13, 14, 15, 16, 17], [20]]
Code
Applying this tool, we make a generator function that finds ranges of consecutive numbers.
def find_ranges(iterable):
"""Yield range of consecutive numbers."""
for group in mit.consecutive_groups(iterable):
group = list(group)
if len(group) == 1:
yield group[0]
else:
yield group[0], group[-1]
iterable = [2, 3, 4, 5, 12, 13, 14, 15, 16, 17, 20]
list(find_ranges(iterable))
# [(2, 5), (12, 17), 20]
The source implementation emulates a classic recipe (as demonstrated by @Nadia Alramli).
Note: more_itertools
is a third-party package installable via pip install more_itertools
.
group together consecutive numbers in a list
You could use negative indexing:
def group_by_missing(seq):
if not seq:
return seq
grouped = [[seq[0]]]
for x in seq[1:]:
if x == grouped[-1][-1] + 1:
grouped[-1].append(x)
else:
grouped.append([x])
return grouped
Example Usage:
>>> lst = [1, 2, 3, 4, 5, 12, 13, 14, 15, 20, 21, 22, 23, 30, 35, 36, 37, 38, 39, 40]
>>> group_by_missing(lst)
[[1, 2, 3, 4, 5], [12, 13, 14, 15], [20, 21, 22, 23], [30], [35, 36, 37, 38, 39, 40]]
Identify groups of varying continuous numbers in a list
You can create an iterator to help grouping and try to pull the next element from the following group which will be the end of the previous group:
def ranges(lst):
it = iter(lst)
next(it) # move to second element for comparison
grps = groupby(lst, key=lambda x: (x - next(it, -float("inf"))))
for k, v in grps:
i = next(v)
try:
step = next(v) - i # catches single element v or gives us a step
nxt = list(next(grps)[1])
yield xrange(i, nxt.pop(0), step)
# outliers or another group
if nxt:
yield nxt[0] if len(nxt) == 1 else xrange(nxt[0], next(next(grps)[1]), nxt[1] - nxt[0])
except StopIteration:
yield i # no seq
which give you:
In [2]: l1 = [2, 3, 4, 5, 8, 10, 12, 14, 13, 14, 15, 16, 17, 20, 21]
In [3]: l2 = [2, 4, 6, 8, 12, 13, 14, 15, 16, 17, 20]
In [4]: l3 = [13, 14, 15, 16, 17, 18]
In [5]: s1 = [i + 10 for i in xrange(0, 11, 2)]
In [6]: s2 = [30]
In [7]: s3 = [i + 40 for i in xrange(45)]
In [8]: l4 = s1 + s2 + s3
In [9]: l5 = [1, 2, 5, 6, 9, 10]
In [10]: l6 = {1, 2, 3, 5, 6, 9, 10, 13, 19, 21, 22, 23, 24}
In [11]:
In [11]: for l in (l1, l2, l3, l4, l5, l6):
....: print(list(ranges(l)))
....:
[xrange(2, 5), xrange(8, 14, 2), xrange(13, 17), 20, 21]
[xrange(2, 8, 2), xrange(12, 17), 20]
[xrange(13, 18)]
[xrange(10, 20, 2), 30, xrange(40, 84)]
[1, 2, 5, 6, 9, 10]
[xrange(1, 3), 5, 6, 9, 10, 13, 19, xrange(21, 24)]
When the step is 1
it is not included in the xrange output.
Group consecutive integers together
As you have lists of consecutive numbers, I suggest you to use range
objects instead of list
s:
d, head = {}, None
for x in l:
if head is None or x != d[head].stop:
head = x
d[head] = range(head, x+1)
Identify groups of continuous numbers from consecutive list in python
L1 = [5,3,2,7,1]
L2 = [3,5,6,8,9,21,2]
L3 = [5,3,6,7,3,9]
cons_l = []
L = [L2] + [L3] #+[L4] #+ ...+ ..... ### Add any number of list here..
j = 0
for l1 in L1:
cons_l.append([])
cons_l[j].append(l1)
for l in range(0, len(L)):
if l1+l+1 in L[l]:
cons_l[j].append(l1+l+1)
else:
del cons_l[j]
j -= 1
break
j += 1
print cons_l
Find groups of continuous integers in a list in Java
try this
public static void main(String[] args) {
List<Integer> list=Arrays.asList(2,3,4,5,8,10,11,12,15,16,17,18,19,25);
List<List<Integer>>lList=new ArrayList<List<Integer>>(); //list of list of integer
System.out.println("list:" + list);
int i=0;
int start=0;
List<Integer> sList=new ArrayList<Integer>(2);
for( i = 1; i <list.size();i++){
if( list.get(i - 1) + 1 != list.get(i)){
sList.add(list.get(start));
sList.add(list.get(i-1));
lList.add(sList);
sList=new ArrayList<Integer>(2);
start=i;
}
}
sList.add(list.get(start)); // for last range
sList.add(list.get(list.size()-1));
lList.add(sList);
System.out.println("Range :"+lList);
}
output :
list:[2, 3, 4, 5, 8, 10, 11, 12, 15, 16, 17, 18, 19, 25]
Range :[[2, 5], [8, 8], [10, 12], [15, 19], [25, 25]]
From a list of random numbers, how to identify five consecutive numbers and separate them in a new list?
There's a related question, Identify groups of continuous numbers in a list. Using a version of Nadia Alramli's solution, we can get all the subsequences of consecutive numbers, then filter out ones shorter than 5:
from itertools import groupby
IDs = []
# Number minus index gives offset. Repeated offsets mean consecutive numbers.
consecutive_numbers = groupby(enumerate(flags), lambda x: x[1]-x[0])
for _offset, g in consecutive_numbers:
numbers = [x[1] for x in g]
if len(numbers) >= 5:
IDs.append(numbers)
print(IDs)
Output:
[[3, 4, 5, 6, 7]]
Edit: blhsing's answer is very similar to mine but a lot cleaner. Here's how it would look integrated with mine:
from itertools import groupby, count
indexes = count()
# Number minus index gives offset. Repeated offsets mean consecutive numbers.
consecutive_numbers = groupby(flags, lambda n: n-next(indexes))
IDs = [g for _offset, (*g,) in consecutive_numbers if len(g) >= 5]
print(IDs)
I hope this is easier to read, if nothing else.
I'm assuming flags
is always in sorted order.
Related Topics
Is There Any Pythonic Way to Combine Two Dicts (Adding Values For Keys That Appear in Both)
How to Understand Closure in a Lambda
How to Search For a String in Text Files
Updating Gui Elements in Multithreaded Pyqt
How to Split the Definition of a Long String Over Multiple Lines
How to Test If a String Contains One of the Substrings in a List, in Pandas
Simpler Way to Create Dictionary of Separate Variables
What Is Getattr() Exactly and How to Use It
Py2Exe - Generate Single Executable File
How to Check If a Variable Exists
Use Numpy Array in Shared Memory For Multiprocessing
Numpy 'Logical_Or' For More Than Two Arguments