11
$\begingroup$

I'm not a math-guy really (a programmer actually) and this is my first question. And excuse me if I can not explain my problem good.

The problem is I have a sequence of integers and I want to detect if they are consecutive or not. e.g.

a1 = {1, 2, 3, 4} (* consecutive *)

a2 = {0, 1} (* consecutive *)

a3 = {0, 1, 2, 4} (* non-consecutive *)

a4 = {3, 4, 5, 6} (* consecutive *)

a5 = {3, 5, 6, 7} (* non-consecutive *)

a6 = {2, 3, 4} (* consecutive *)

The numbers come from a list's indexes that a user selected in UI. Actually I want to see if he selects a consecutive rows or not. Is there any way (sure there is :)) to check this without walking through all items in the list? I mean for example by using the first and last number in the list etc?

Update:

Note:

The numbers:

  1. they are integers,
  2. they are ascending,
  3. no repeats
$\endgroup$
2
  • $\begingroup$ Related: Find continuous sequences inside a list $\endgroup$ Dec 21, 2013 at 13:11
  • $\begingroup$ Perhaps what is required here is a modification of (the poorly documented) PermutationQ from the old Combinatorica package? PermutationQAlt[e_List] := Sort[e - Min[e] + 1] === Range@Length@e (see here). PermutationQAlt /@ {a1, a2, a3, a4, a5, a6, {1, 3, 3, 3, 5}, {1, 1, 4, 4, 5}} gives {True, True, False, True, False, True, False, False} $\endgroup$
    – user1066
    Feb 21, 2017 at 11:54

5 Answers 5

16
$\begingroup$

IF you can assume 1) they are integers, 2) they are ascending, and 3) no repeats, THEN your last idea should work

Last[list]-First[list]==Length[list]-1

Or you could

Union[Differences[list]]=={1}

Without assumptions (2) and (3):

Union[Differences[Sort[list]]]=={1}
$\endgroup$
2
  • $\begingroup$ On second thought, I kind of dislike the formulation of the assumptions. That we are concerned with integers is explicitly specified by the OP. Furthermore, there seems to be a mix up between what is the desired result and what we can assume about the input list. If the desired result is for a list like {1,1} we should give true, then the code with Last, First and Length is useless. If not, then it will yield the right result whenever the list is non-decreasing, that is it works even if there are repeats. In this case you give False for {1,1} as desired. $\endgroup$ Dec 21, 2013 at 17:09
  • $\begingroup$ what is the way to do this if you cannot assume ascending or repeats? but provided you have integers $\endgroup$
    – PirateApp
    May 16, 2018 at 12:19
14
$\begingroup$

A short one:

consecutiveQ = Most[#] == Rest[#] - 1 &
$\endgroup$
2
  • $\begingroup$ Very clean, and I can't think of anything wrong with it at the moment. Theoretically it will be a bit slower on long lists that would be eliminated by one of my "sanity checks" but it probably doesn't matter in practice. $\endgroup$
    – Mr.Wizard
    Dec 21, 2013 at 13:57
  • $\begingroup$ Very nice, and likely very fast. $\endgroup$
    – DavidC
    Dec 21, 2013 at 16:44
6
$\begingroup$

From Stack Overflow: How to test if a list contains consecutive integers in Mathematica?
See rcollyer's comparative timings.

My concise form of belisarius's method from that thread was:

Range[##, Sign[#2 - #]]& @@ #[[{1, -1}]] == # &;

It checks for consecutive numbers in either direction. It however will consume memory or outright fail in the case where the first and last values in the test list are far apart because of the Range generation:

Range[##, Sign[#2 - #]]& @@ #[[{1, -1}]] == # &[{1, 2, 1*^50}]

Range::range: Range specification in Range[1,100000000000000000000000000000000000000000000000000,1] does not have appropriate bounds. >>

Here is an updated approach that does some sanity checks first:

consecutiveQ[x : {first_, ___, last_}] :=
  And[
    Min[x] == first,
    Max[x] == last,
    Length[x] == last - first + 1,
    Range[first, last] == x
  ]

consecutiveQ /@ {a1, a2, a3, a4, a5, a6}
{True, True, False, True, False, True}

It only checks for forward-increasing sequences as that is what is shown in this question. It could be easily adapted for backward sequences as well if needed.

If your valid input lists will always contain integers you could add the condition:

VectorQ[x, IntegerQ]

Otherwise as written the the test will return True for e.g. consecutiveQ[{7., 8., 9.}].

$\endgroup$
4
  • $\begingroup$ Now I get your business model - you provide a translation service, right? $\endgroup$
    – Yves Klett
    Dec 21, 2013 at 13:14
  • $\begingroup$ @Yves We'll call it a business when I start getting paid. :^) $\endgroup$
    – Mr.Wizard
    Dec 21, 2013 at 13:15
  • $\begingroup$ Yes, a sore point :D As a beginner perusing your solution though, I would really start to search for alternative languages. $\endgroup$
    – Yves Klett
    Dec 21, 2013 at 13:16
  • $\begingroup$ @Yves Or hire a consultant. ;-) :D $\endgroup$
    – Mr.Wizard
    Dec 21, 2013 at 13:19
5
$\begingroup$

Method 1

How about simply…?

 consecQ[a_]:= a===Range[a[[1]],a[[-1]]]

This is based on the assumption that the Mathematica can handle the Range size.

Testing

consecQ[{0, 3, 2, 1, 4}]

False

consecQ[{0, 1, 2, 3, 4}]

True


Method2

@A.G. notes that the following can be used if one is concerned about the length of list.

If[Last@a - First@a == Length[a] - 1, a == Range[First@a, Last@a], False]

The idea is to first check whether the length of the list is consistent with the first and last elements.


Method 3

This may not be efficient, but it does the job.

Assuming that the list consists of integers.

consecQ2[a_] := Union[Differences[a]] == {1}

Testing

consecQ2[{0, 1, 2, 3, 4}]
consecQ2[{0, 3, 2, 1, 4}]
consecQ2[{4, 3, 2, 1, 0}]

True
False
False

$\endgroup$
9
  • $\begingroup$ The problem with this is noted in my answer; if the difference between the first and last element is large you may hang your machine. $\endgroup$
    – Mr.Wizard
    Dec 21, 2013 at 13:51
  • 3
    $\begingroup$ Call me insane, but it's not something I worry about. $\endgroup$
    – DavidC
    Dec 21, 2013 at 13:54
  • $\begingroup$ If you don't mind, why not? There is no specific constraint on the size of the last integer in the list, so it seems like a valid concern. $\endgroup$
    – Mr.Wizard
    Dec 21, 2013 at 13:58
  • $\begingroup$ It is generally the case that Mathematica can not handle numbers or list lengths beyond certain limits. By default, I prefer to look for a simple solution within these constraints. If I were a NASA engineer or a microchip designer, I would probably take a different stance. $\endgroup$
    – DavidC
    Dec 21, 2013 at 14:05
  • 2
    $\begingroup$ @Mr.Wizard There is an implicit constraint in that the OP said that the indices come from selections a user makes in a UI. Now if you want to argue that the UI might have $10^{10}$ rows and we need to optimize for that, then that's silly. $\endgroup$
    – rm -rf
    Dec 21, 2013 at 17:52
0
$\begingroup$

Simply subtract sum of both edges:

ConsecutiveQ[list_] := 
 Last[list] (Last[list] + 1)/2 - (First[list] - 1) First[list]/2 == 
  Total[list]

Test:

ConsecutiveQ /@ {a1, a2, a3, a4, a5, a6}

{True, True, False, True, False, True}
$\endgroup$
2
  • $\begingroup$ This doesn't work. For example, ConsecutiveQ[{1, 3, 3, 3, 5}] and ConsecutiveQ[{1, 1, 4, 4, 5}] return True, as will any five element sequence {1, a, b, c, 5} for which a + b + c = 9 (=2 + 3 + 4) $\endgroup$
    – Aky
    Dec 21, 2013 at 19:35
  • $\begingroup$ I should mention here that my previous comment doesn't hold if we make the assumptions in the update posted (a short while ago) by OP in his question. (Although in that case there are much simpler ways of testing, as already indicated in other answers.) $\endgroup$
    – Aky
    Dec 21, 2013 at 21:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.