Finding largest Range in a list
If speed is important, I think that this is a typical example in which compilation of a straightforward algorithm gives better results than making use of the advanced functions of Mathematica. Here is such a compiled function:
f= Compile[{{lst, _Integer, 1}}, Module[{result=0,counting=0},
Do[
If[n==counting+1,
counting=n,
If[counting>result, result=counting]; counting=If[n==1, 1, 0] ],
{n, lst}];
Max[{result, counting}]]]
On my computer, for a list of 10^6 positive integers, this function is more than 20 times faster than the splitting technique:
SeedRandom[42];
list=RandomInteger[{1,10},10^6];
Select[Split[list,#1+1==#2&],#[[1]]==1&]//Max // Timing
f[list] // Timing
fC[list] // Timing
(* {2.418016,5} *)
(* {0.109201,5} *)
(* {0.015600,5} *)
Here the function fC is identical to f, but compiled with the option CompilationTarget->"C". So when available, this gives another factor about 9.
This seems to be substantially faster.
extend[list_List, pos_List /; Length[pos] > 0, depth_Integer] :=
extend[list,
pos[[Flatten[
Position[list[[DeleteCases[Flatten[pos], Length[list]] + 1]],
depth + 1]]]] + 1, depth + 1]
extend[list_List, {}, depth_Integer] := depth - 1
extend[list, Position[list, 1], 1]
Also, using Max
gives negative infinity when there is no element 1 in the list.
This seems analogous to Boyer-Moore. Therefore, a further improvement would be to extend the first matching substring as much as possible (let's say the length of the substring is n
), and then at the second matching substring check to see if it could be longer (by checking the element n
positions after the start of the second matching substring), etc.
SeedRandom[42];
list = RandomInteger[{1, 7}, 1000];
Select[Split[list, #1 + 1 == #2 &], #[[1]] == 1 &] // Max
(* 3*)