简体   繁体   中英

How to see if the list contains consecutive numbers

I want to test if a list contains consecutive integers and no repetition of numbers. For example, if I have

l = [1, 3, 5, 2, 4, 6]

It should return True.

How should I check if the list contains up to n consecutive numbers without modifying the original list? I thought about copying the list and removing each number that appears in the original list and if the list is empty then it will return True.

Is there a better way to do this?

For the whole list, it should just be as simple as

sorted(l) == list(range(min(l), max(l)+1))

This preserves the original list, but making a copy (and then sorting) may be expensive if your list is particularly long.

Note that in Python 2 you could simply use the below because range returned a list object. In 3.x and higher the function has been changed to return a range object, so an explicit conversion to list is needed before comparing to sorted(l)

sorted(l) == range(min(l), max(l)+1))

To check if n entries are consecutive and non-repeating, it gets a little more complicated:

def check(n, l):
    subs = [l[i:i+n] for i in range(len(l)) if len(l[i:i+n]) == n]
    return any([(sorted(sub) in range(min(l), max(l)+1)) for sub in subs])

We can use known mathematics formula for checking consecutiveness, Assuming min number always start from 1

sum of consecutive n numbers 1...n = n * (n+1) /2 


  def check_is_consecutive(l):
        maximum = max(l)
        if sum(l) == maximum * (maximum+1) /2 : 
             return True
        return False

The first code removes duplicates but keeps order:

from itertools import groupby, count

l = [1,2,4,5,2,1,5,6,5,3,5,5]

def remove_duplicates(values):
    output = []
    seen = set()
    for value in values:
        if value not in seen:
            output.append(value)
            seen.add(value)
    return output

l = remove_duplicates(l) # output = [1, 2, 4, 5, 6, 3]

The next set is to identify which ones are in order, taken from here :

def as_range(iterable):
    l = list(iterable)
    if len(l) > 1:
        return '{0}-{1}'.format(l[0], l[-1])
    else:
        return '{0}'.format(l[0])

l = ','.join(as_range(g) for _, g in groupby(l, key=lambda n, c=count(): n-next(c)))

l outputs as: 1-2,4-6,3

You can customize the functions depending on your output.

Once you verify that the list has no duplicates, just compute the sum of the integers between min(l) and max(l) :

def check(l):
    total = 0
    minimum = float('+inf')
    maximum = float('-inf')

    seen = set()

    for n in l:
        if n in seen:
            return False

        seen.add(n)

        if n < minimum:
            minimum = n

        if n > maximum:
            maximum = n

        total += n

    if 2 * total != maximum * (maximum + 1) - minimum * (minimum - 1):
        return False

    return True
import numpy as np
import pandas as pd    

(sum(np.diff(sorted(l)) == 1) >= n) & (all(pd.Series(l).value_counts() == 1))

We test both conditions, first by finding the iterative difference of the sorted list np.diff(sorted(l)) we can test if there are n consecutive integers. Lastly, we test if the value_counts() are all 1, indicating no repeats.

I split your query into two parts part A "list contains up to n consecutive numbers" this is the first line if len(l) != len(set(l)):

And part b, splits the list into possible shorter lists and checks if they are consecutive.

def example (l, n):
    if len(l) != len(set(l)):  # part a
        return False
    for i in range(0, len(l)-n+1):  # part b
        if l[i:i+3] == sorted(l[i:i+3]):
            return True
    return False

l = [1, 3, 5, 2, 4, 6]
print example(l, 3)
def solution(A):
    counter = [0]*len(A)
    limit = len(A)
    for element in A:
        if not 1 <= element <= limit:
            return False
        else:
            if counter[element-1] != 0:
                return False
            else:
                counter[element-1] = 1

    return True

The input to this function is your list.This function returns False if the numbers are repeated. The below code works even if the list does not start with 1.

def check_is_consecutive(l):
    """
    sorts the list and 
    checks if the elements in the list are consecutive
    This function does not handle any exceptions.
    returns true if the list contains consecutive numbers, else False
    """
    l = list(filter(None,l))
    l = sorted(l)
    if len(l) > 1:
        maximum = l[-1]
        minimum = l[0] - 1
        if minimum == 0:
            if sum(l) == (maximum * (maximum+1) /2): 
                return True
            else:
                return False
        else:
            if sum(l) == (maximum * (maximum+1) /2) - (minimum * (minimum+1) /2) : 
                return True
            else:
                return False
    else:
        return True

1.

l.sort()

2.

 for i in range(0,len(l)-1))) print(all((l[i+1]-l[i]==1)

list must be sorted!

lst = [9,10,11,12,13,14,15,16]

final = True if len( [ True for x in lst[:-1] for y in lst[1:] if x + 1 == y ] ) == len(lst[1:]) else False

i don't know how efficient this is but it should do the trick.

With sorting

In Python 3, I use this simple solution:

def check(lst):
    lst = sorted(lst)
    if lst:
        return lst == list(range(lst[0], lst[-1] + 1))
    else:
        return True

Note that, after sorting the list, its minimum and maximum come for free as the first ( lst[0] ) and the last ( lst[-1] ) elements. I'm returning True in case the argument is empty, but this decision is arbitrary. Choose whatever fits best your use case.

In this solution, we first sort the argument and then compare it with another list that we know that is consecutive and has no repetitions.

Without sorting

In one of the answers, the OP commented asking if it would be possible to do the same without sorting the list. This is interesting, and this is my solution:

def check(lst):
    if lst:
        r = range(min(lst), max(lst) + 1) # *r* is our reference
        return (
            len(lst) == len(r)
            and all(map(lst.__contains__, r))
            # alternative: all(x in lst for x in r)
            # test if every element of the reference *r* is in *lst*
        )
    else:
        return True

In this solution, we build a reference range r that is a consecutive (and thus non-repeating) sequence of int s. With this, our test is simple: first we check that lst has the correct number of elements (not more, which would indicate repetitions, nor less, which indicates gaps) by comparing it with the reference. Then we check that every element in our reference is also in lst (this is what all(map(lst.__contains__, r)) is doing: it iterates over r and tests if all of its elements are in lts ).

l = [1, 3, 5, 2, 4, 6]
from itertools import chain


def check_if_consecutive_and_no_duplicates(my_list=None):
    return all(
        list(
            chain.from_iterable(
                [
                    [a + 1 in sorted(my_list) for a in sorted(my_list)[:-1]],
                    [sorted(my_list)[-2] + 1 in my_list],
                    [len(my_list) == len(set(my_list))],
                ]
            )
        )
    )

Add 1 to any number in the list except for the last number(6) and check if the result is in the list. For the last number (6) which is the greatest one, pick the number before it(5) and add 1 and check if the result(6) is in the list.

Here is a really short easy solution without having to use any imports:

range = range(10)
L = [1,3,5,2,4,6]
L = sorted(L, key = lambda L:L)
range[(L[0]):(len(L)+L[0])] == L

>>True

This works for numerical lists of any length and detects duplicates. Basically, you are creating a range your list could potentially be in, editing that range to match your list's criteria (length, starting value) and making a snapshot comparison. I came up with this for a card game I am coding where I need to detect straights/runs in a hand and it seems to work pretty well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM