Python: find out whether a list of integers is coherent

2024/11/17 21:33:59

I am trying to find out whether a list of integers is coherent or 'at one stretch', meaning that the difference between two neighboring elements must be exactly one and that the numbers must be increasing monotonically. I found a neat approach where we can group by the number in the list minus the position of the element in the list -- this difference changes when the numbers are not coherent. Obviously, there should be exactly one group when the sequence does not contain gaps or repetitions.

Test:

>>> l1 = [1, 2, 3, 4, 5, 6]
>>> l2 = [1, 2, 3, 4, 5, 7]
>>> l3 = [1, 2, 3, 4, 5, 5]
>>> l4 = [1, 2, 3, 4, 5, 4]
>>> l5 = [6, 5, 4, 3, 2, 1]
>>> def is_coherent(seq):
...     return len(list(g for _, g in itertools.groupby(enumerate(seq), lambda (i,e): i-e))) == 1
... 
>>> is_coherent(l1)
True
>>> is_coherent(l2)
False
>>> is_coherent(l3)
False
>>> is_coherent(l4)
False
>>> is_coherent(l5)
False

It works well, but I personally find that this solution is a bit too convoluted in view of the simplicity of the problem. Can you come up with a clearer way to achieve the same without significantly increasing the code length?

Edit: summary of answers

From the answers given below, the solution

def is_coherent(seq):return seq == range(seq[0], seq[-1]+1)

clearly wins. For small lists (10^3 elements), it is on the order of 10 times faster than the groupby approach and (on my machine) still four times faster than the next best approach (using izip_longest). It has the worst scaling behavior, but even for a large list with 10^8 elements it is still two times faster than the next best approach, which again is the izip_longest-based solution.

Relevant timing information obtained with timeit:

Testing is_coherent_groupby...small/large/larger/verylarge duration: 8.27 s, 20.23 s, 20.22 s, 20.76 slargest/smallest = 2.51
Testing is_coherent_npdiff...small/large/larger/verylarge duration: 7.05 s, 15.81 s, 16.16 s, 15.94 slargest/smallest = 2.26
Testing is_coherent_zip...small/large/larger/verylarge duration: 5.74 s, 20.54 s, 21.69 s, 24.62 slargest/smallest = 4.28
Testing is_coherent_izip_longest...small/large/larger/verylarge duration: 4.20 s, 10.81 s, 10.76 s, 10.81 slargest/smallest = 2.58
Testing is_coherent_all_xrange...small/large/larger/verylarge duration: 6.52 s, 17.06 s, 17.44 s, 17.30 slargest/smallest = 2.65
Testing is_coherent_range...small/large/larger/verylarge duration: 0.96 s, 4.14 s, 4.48 s, 4.48 slargest/smallest = 4.66

Testing code:

import itertools
import numpy as np
import timeitsetup = """
import numpy as np
def is_coherent_groupby(seq):return len(list(g for _, g in itertools.groupby(enumerate(seq), lambda (i,e): i-e))) == 1def is_coherent_npdiff(x):return all(np.diff(x) == 1)def is_coherent_zip(seq):return all(x==y+1 for x, y in zip(seq[1:], seq))def is_coherent_izip_longest(l):return all(a==b for a, b in itertools.izip_longest(l, xrange(l[0], l[-1]+1)))def is_coherent_all_xrange(l):return all(l[i] + 1 == l[i+1] for i in xrange(len(l)-1))def is_coherent_range(seq):return seq == range(seq[0], seq[-1]+1)small_list = range(10**3)
large_list = range(10**6)
larger_list = range(10**7)
very_large_list = range(10**8)
"""fs = ['is_coherent_groupby','is_coherent_npdiff','is_coherent_zip','is_coherent_izip_longest','is_coherent_all_xrange','is_coherent_range']for n in fs:print "Testing %s..." % nt1 = timeit.timeit('%s(small_list)' % n, setup,number=40000)      t2 = timeit.timeit('%s(large_list)' % n, setup,number=100)     t3 = timeit.timeit('%s(larger_list)' % n, setup,number=10)t4 =  timeit.timeit('%s(very_large_list)' % n, setup,number=1)print "   small/large/larger/verylarge duration: %.2f s, %.2f s, %.2f s, %.2f s" % (t1, t2, t3, t4)print "   largest/smallest = %.2f" % (t4/t1)

Test machine:

  • Linux 3.2.0 (Ubuntu 12.04)
  • Python 2.7.3 (gcc 4.1.2)
  • numpy 1.6.2 built with Intel compiler
  • CPU: E5-2650 @ 2.00GHz
  • 24 GB of memory
Answer

how bout

sorted_list = sorted(my_list)
return sorted_list == range(sorted_list[0],sorted_list[-1]+1)

or if its only coherent if it is already sorted

return my_list == range(my_list[0],my_list[-1]+1)

if you are using python 3 you will need list(range(...))

https://en.xdnf.cn/q/71140.html

Related Q&A

Create resizable/multiline Tkinter/ttk Labels with word wrap

Is it possible to create a multi-line label with word wrap that resizes in sync with the width of its parent? In other words the wordwrap behavior of Notepad as you change the width of the NotePad win…

Unicode, regular expressions and PyPy

I wrote a program to add (limited) unicode support to Python regexes, and while its working fine on CPython 2.5.2 its not working on PyPy (1.5.0-alpha0 1.8.0, implementing Python 2.7.1 2.7.2), both run…

Python str object has no attribute read

Python 3.3.2 import json & urllib.requestJson[{"link":"www.google.com","orderid":"100000222"}, {"link":"www.google.com","orderid&quo…

Efficient upsert of pandas dataframe to MS SQL Server using pyodbc

Im trying to upsert a pandas dataframe to a MS SQL Server using pyodbc. Ive used a similar approach before to do straight inserts, but the solution Ive tried this time is incredibly slow. Is there a mo…

Comparison on the basis of min function

How exactly does the min function work for lists in python ?For example,num = [1,2,3,4,[1,2,3]]num2 = [1,2,3,4,5]min(num,num2) gives num2 as the result. Is the comparison value based or length based ?

Python Pandas rolling aggregate a column of lists

I have a simple dataframe df with a column of lists lists. I would like to generate an additional column based on lists.The df looks like:import pandas as pd lists={1:[[1]],2:[[1,2,3]],3:[[2,9,7,9]],4:…

Easy way of overriding default methods in custom Python classes?

I have a class called Cell:class Cell:def __init__(self, value, color, size):self._value = valueself._color = colorself._size = size# and other methods...Cell._value will store a string, integer, etc. …

Return first non NaN value in python list

What would be the best way to return the first non nan value from this list?testList = [nan, nan, 5.5, 5.0, 5.0, 5.5, 6.0, 6.5]edit:nan is a float

How to subplot pie chart in plotly?

How can I subplot pie1 in fig, so it be located at the first position. this is how I am doing it but it doesnt work out import pandas as pdimport numpy as npimport seaborn as snsimport plotly.offline a…

Example of use \G in negative variable-length lookbehinds to limit how far back the lookbehind goes

In the pypi page of the awesome regex module (https://pypi.python.org/pypi/regex) it is stated that \G can be used "in negative variable-length lookbehinds to limit how far back the lookbehind goe…