# Pick elements from list "separately"

I have the following list I want to pick elements from:

mylist = {1, 5, 7, 3, 4, 7, 2, 9, 9, 1, 10, 12, 2, 64, 34, 64}


I have another list with 0's and 1's which is my selector:

selector = {1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1}


I want to select all the entries from mylist where selector has a 1. I know I can do this via:

Pick[mylist,selector,1]


BUT: Pick gives me all the selected elements from mylist together like this:

{1, 5, 7, 7, 2, 9, 1, 10, 34, 64}


I want the elements which are separated in selector by a 0 to be separate lists. That is, as a result I want to have a list of lists like this:

{{1,5,7},{7,2},{9,1,10},{34,64}}


Any help appreciated!

mylist = {1, 5, 7, 3, 4, 7, 2, 9, 9, 1, 10, 12, 2, 64, 34, 64};
selector = {1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1};

pick = Pick[mylist, selector, 1];

split = Length /@ Cases[Split[selector], {1 ...}]


{3, 2, 3, 2}

InternalPartitionRagged[pick, split]


{{1, 5, 7}, {7, 2}, {9, 1, 10}, {34, 64}}

Update

Since V 11.2 we can use TakeList

TakeList[pick, split]


{{1, 5, 7}, {7, 2}, {9, 1, 10}, {34, 64}}

• Interesting solution, never would have thought of that :). Thanks very much! Commented Nov 28, 2015 at 17:59

You can combine Map, Take, and SequencePosition:

Map[Take[mylist, #] &,
SequencePosition[selector, {1 ..}, Overlaps -> False]]

(* {{1, 5, 7}, {7, 2}, {9, 1, 10}, {34, 64}} *)

– eldo
Commented Nov 28, 2015 at 20:49

Because your selector is 0 or 1, SplitBy can be used as follows.

Select[SplitBy[mylist*selector, Positive], #[[1]] > 0 &]

• Select[SplitBy[mylist*selector, # != 0 &], #[[1]] != 0 &] would also work for negative numbers - +1 anyway
– eldo
Commented Nov 28, 2015 at 20:45

You can find positions where differences of selector is nonzero. Then you can take corresponding sublists. This straightforward solution is relatively fast (two times faster then eldo's solution, which is already very efficient)

list = {1, 5, 7, 3, 4, 7, 2, 9, 9, 1, 10, 12, 2, 64, 34, 64};
selector = {1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1};

pick[list_, sel_] :=
Take[list, #] & /@ Transpose@{#[[;; ;; 2]], #[[2 ;; ;; 2]] - 1} &@
Pick[Range@Length@#, #, 1] &@Abs@Differences@Join[{0}, sel, {0}];

pick[list, selector]
(* {{1, 5, 7}, {7, 2}, {9, 1, 10}, {34, 64}} *)

n = 1000000;
list = RandomInteger[100, n];
selector = RandomInteger[1, n];

pick[list, selector]; // RepeatedTiming
(* {0.706, Null} *)

 SequenceSplit[mylist selector,{0}]

(* {{1, 5, 7}, {7, 2}, {9, 1, 10}, {34, 64}} *)

Map[Take[mylist, #] &,
Map[Flatten[#] &,
FindClusters[Position[selector, 1]]] //. {w___, {q_, __, x_},
k___} :> {w, {q, x}, k}]

{{1, 5, 7}, {7, 2}, {9, 1, 10}, {34, 64}}


Using TakeList:

Clear["Global*"];
mylist = {1, 5, 7, 3, 4, 7, 2, 9, 9, 1, 10, 12, 2, 64, 34, 64};
selector = {1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1};

lens = Map[Length]@Split[selector];
pos = Position[Split[selector], {1 ..}];
Extract[TakeList[mylist, lens], pos]


{{1, 5, 7}, {7, 2}, {9, 1, 10}, {34, 64}}

f = InternalCopyListStructure[Split @ #2, #][[2 - First @ #2 ;; ;; 2]] &;

f[mylist, selector]

{{1, 5, 7}, {7, 2}, {9, 1, 10}, {34, 64}}


Lots of nice answers already but coming to this question late here are my ideas.

Application of Szabolcs's How to efficiently find positions of duplicates? with adaptations:

fn1[a_, b_] :=
a[[#]] & /@ SplitBy[Range@Length@a, b[[#]] &][[2 - b[[1]] ;; ;; 2]]


Application of my intervals from Find continuous sequences inside a list (load it first)

fn2[a_, b_] :=
Take[a, #] & /@ intervals @ SparseArray[b]["AdjacencyLists"]


Test:

fn1[mylist, selector]

fn2[mylist, selector]

{{1, 5, 7}, {7, 2}, {9, 1, 10}, {34, 64}}

{{1, 5, 7}, {7, 2}, {9, 1, 10}, {34, 64}}

list={1, 5, 7, 3, 4, 7, 2, 9, 9, 1, 10, 12, 2, 64, 34, 64};

selector = {1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1};


Another way to do this is as follows:

sel=!FreeQ[#,KeyValuePattern[{1->a_}]]&;

Values@DeleteCases[
Rule[0,a_],2]


{{1,5,7},{7,2},{9,1,10},{34,64}}

list = {1, 5, 7, 3, 4, 7, 2, 9, 9, 1, 10, 12, 2, 64, 34, 64};

selector = {1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1};


Using TakeList (new in 11.2) and SequenceCases

TakeList[
Pick[list, selector, 1],
SequenceCases[selector, x : {1 ..} :> Length[x]]]
`

{{1, 5, 7}, {7, 2}, {9, 1, 10}, {34, 64}}