# Select cases from a list

I have a list in the form :

{1,1,1,0,-1,-1,1,1,1,0,0,0,0,-1,-1}


No I'm trying to select only those sequences which start with 1 have a zero (or many zeros) between and are followed by -1. For example: 1,0,-1 | 1,0,0,0,0,-1

I tried to use Cases, but I'm not sure how to define the pattern. Can someone help me out please?

• Closely related: (23454) Apr 30, 2014 at 7:19

One way is this

ReplaceList[{1, 1, 1, 0, -1, -1, 1, 1, 1, 0, 0, 0, 0, -1, -1},
{___, a : PatternSequence[1, 0 .., -1], ___} :> {a}]

(* {{1, 0, -1}, {1, 0, 0, 0, 0, -1}} *)


If you need the position, length or some other information about the location of the match inside the list, you could do it like this:

ReplaceList[{1, 1, 1, 0, -1, -1, 1, 1, 1, 0, 0, 0,  0, -1, -1},
{s___, a : PatternSequence[1, 0 .., -1], ___} :>
With[{l = Length[{s}]}, {{l + 1, l + Length[{a}]}, {a}}]]

(* {{{3, 5}, {1, 0, -1}}, {{9, 14}, {1, 0, 0, 0, 0, -1}}} *)


This stores the start elements before the matching pattern in s and you can calculate all information from this. Here, I give the start- and end-position of the pattern inside the list.

• Thanks! Is there any way how to find the position of the pattern in the list? Apr 20, 2014 at 14:50
• @holistic Yes, this is easily possible. Please see my edit in the answer. Apr 20, 2014 at 17:41

Be aware, the method posted by halirutan, while concise, will be glacially slow on larger lists. Here's a method whipped up cigar-thinking that is much faster. Just a WIP, there's probably 2-3X performance improvement left in it (e.g., using something other than membership testing), but again, just barfed this out during leisure time (edit, updated code, much faster, will update timings from older code as patience permits):

getSeq3[list_] :=
Module[{z = Split[Select[Pick[Range@Length@list, list, 0],
1 < # < Length@list &], #2 == #1 + 1 &][[All, {1, -1}]]},

{# + {-1, 1}, list[[#[[1]] - 1 ;; #[[2]] + 1]]} & /@
Select[z, (list[[#[[1]] - 1]] == 1 && list[[#[[2]] + 1]] == -1) &]]


A quick timing comparison (lists generated with RandomInteger[{-1,1},size], on a netbook so expect 10-20X faster on "real" machines):

Updated timings from improvements:

An even faster result can be had by moving things into the string domain:

getSeqSP[list_] :=
Module[{sp = StringPosition[FromCharacterCode[list + 2],
FromCharacterCode[3] ~~ Repeated[FromCharacterCode[2], {1, Infinity}] ~~
FromCharacterCode[1]]},

Transpose[{sp, Rest@Extract[list, Prepend[Transpose[{Span @@@ sp}], {{}}]]}]]


Timings are so quick, even on the netbook they are below resolution:

On larger lists, this is order of magnitude + faster than already fast methods above. Probably about as fast as possible without resorting to compiled methods.

• Thanks rasher! Since I also want to search larger lists..this is very helpful!! Apr 21, 2014 at 8:56
• @holistic: Glad you find it useful. Thanks again for one of those "simple" but interesting problems!
– ciao
Apr 24, 2014 at 0:22
• Congrats on having top rep this quarter, as well having 7,666 rep, which is a nice number :P. Nice tables here too, ratios of timings are a good thing. +1 Apr 24, 2014 at 10:56
• @JacobAkkerboom: Not even sure what that means, other than I have too much spare time ;-) but thanks!
– ciao
Apr 24, 2014 at 22:35
list = {1, 1, 1, 0, -1, -1, 1, 1, 1, 0, 0, 0, 0, -1, -1};


This is a custom-tailored case for SequenceCases (new in 10.1)

SequenceCases[list, {1, 0 .., -1}]


{{1, 0, -1}, {1, 0, 0, 0, 0, -1}}

Using SequencePosition, Span and Extract:

list = {1, 1, 1, 0, -1, -1, 1, 1, 1, 0, 0, 0, 0, -1, -1};

Extract[#, Span @@@ {#} & /@ SequencePosition[#, {1, 0 .., -1}]] &@list

(*{{1, 0, -1}, {1, 0, 0, 0, 0, -1}}*)


Or using SequenceSplit:

Most /@ SequenceSplit[list, {1, 0 ..., 1}]

(*{{1, 0, -1}, {1, 0, 0, 0, 0, -1}}*)


Using SequenceReplace and Cases:

Cases[SequenceReplace[list, p : {1, 0 .., -1} :> p], _List]

(*{{1, 0, -1}, {1, 0, 0, 0, 0, -1}}*)