How to detect if a sequence of integers is consecutive

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
-
–  Jacob Akkerboom Dec 21 '13 at 13:11

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}

-
+1 or the code when the assumptions hold. –  Jacob Akkerboom Dec 21 '13 at 13:16
+1 Excellent thanks a lot –  Javad_Amiry Dec 21 '13 at 15:54
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. –  Jacob Akkerboom Dec 21 '13 at 17:09

A short one:

consecutiveQ = Most[#] == Rest[#] - 1 &

-
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. –  Mr.Wizard Dec 21 '13 at 13:57
Very nice, and likely very fast. –  David Carraher Dec 21 '13 at 16:44

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 our 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 check 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.}].

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

Method 1

 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

-
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. –  Mr.Wizard Dec 21 '13 at 13:51
Call me insane, but it's not something I worry about. –  David Carraher Dec 21 '13 at 13:54
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. –  Mr.Wizard Dec 21 '13 at 13:58
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. –  David Carraher Dec 21 '13 at 14:05
@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. –  rm -rf Dec 21 '13 at 17:52

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}

-
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) –  Aky Dec 21 '13 at 19:35
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.) –  Aky Dec 21 '13 at 21:53