21
$\begingroup$

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!

$\endgroup$

9 Answers 9

22
$\begingroup$
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}

Internal`PartitionRagged[pick, split]

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

$\endgroup$
1
  • $\begingroup$ Interesting solution, never would have thought of that :). Thanks very much! $\endgroup$
    – holistic
    Nov 28, 2015 at 17:59
20
$\begingroup$

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}} *) 
$\endgroup$
1
  • 3
    $\begingroup$ I should upgrade :) $\endgroup$
    – eldo
    Nov 28, 2015 at 20:49
18
$\begingroup$

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

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

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} *)
$\endgroup$
4
$\begingroup$
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}}
$\endgroup$
4
$\begingroup$
 SequenceSplit[mylist selector,{0}]

 (* {{1, 5, 7}, {7, 2}, {9, 1, 10}, {34, 64}} *)
$\endgroup$
3
$\begingroup$

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}}
$\endgroup$
3
$\begingroup$

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}}

$\endgroup$
3
$\begingroup$
f = Internal`CopyListStructure[Split @ #2, #][[2 - First @ #2 ;; ;; 2]] &;


f[mylist, selector]
{{1, 5, 7}, {7, 2}, {9, 1, 10}, {34, 64}}
$\endgroup$

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.