Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting consecutive integers in a list [duplicate]

I have a list containing data as such:

[1, 2, 3, 4, 7, 8, 10, 11, 12, 13, 14] 

I'd like to print out the ranges of consecutive integers:

1-4, 7-8, 10-14 

Is there a built-in/fast/efficient way of doing this?

like image 232
James Avatar asked Mar 02 '10 09:03

James


People also ask

How do you check if the numbers in a list are consecutive numbers?

With numpy diff and sorted The diff function in numpy can find the difference between each of the numbers after they are sorted. We take a sum of this differences. That will match the length of the list if all numbers are consecutive.

How do you find consecutive numbers?

What are Consecutive Numbers? Numbers that follow each other continuously in the order from smallest to largest are called consecutive numbers. For example: 1, 2, 3, 4, 5, 6, and so on are consecutive numbers.


2 Answers

From the docs:

>>> 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): ...     print map(itemgetter(1), g) ... [1] [4, 5, 6] [10] [15, 16, 17, 18] [22] [25, 26, 27, 28] 

You can adapt this fairly easily to get a printed set of ranges.

like image 130
Dominic Rodger Avatar answered Sep 23 '22 02:09

Dominic Rodger


A short solution that works without additional imports. It accepts any iterable, sorts unsorted inputs, and removes duplicate items:

def ranges(nums):     nums = sorted(set(nums))     gaps = [[s, e] for s, e in zip(nums, nums[1:]) if s+1 < e]     edges = iter(nums[:1] + sum(gaps, []) + nums[-1:])     return list(zip(edges, edges)) 

Example:

>>> ranges([2, 3, 4, 7, 8, 9, 15]) [(2, 4), (7, 9), (15, 15)]  >>> ranges([-1, 0, 1, 2, 3, 12, 13, 15, 100]) [(-1, 3), (12, 13), (15, 15), (100, 100)]  >>> ranges(range(100)) [(0, 99)]  >>> ranges([0]) [(0, 0)]  >>> ranges([]) [] 

This is the same as @dansalmo's solution which I found amazing, albeit a bit hard to read and apply (as it's not given as a function).

Note that it could easily be modified to spit out "traditional" open ranges [start, end), by e.g. altering the return statement:

    return [(s, e+1) for s, e in zip(edges, edges)] 
like image 30
coldfix Avatar answered Sep 20 '22 02:09

coldfix