Identify Groups of Continuous Numbers in a List

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 lists:

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



Leave a reply



Submit