11
$\begingroup$

I want to take enough elements from list such that 2 is included 3 times.

SeedRandom[1]
list = RandomChoice[{.2, .5, .3} -> {1, 2, 3}, 20]

{3,1,3,1,2,1,2,2,2,3,2,3,2,2,3,3,3,2,2,2}

I hope to get {3,1,3,1,2,1,2,2}. I think I make no mistake in my code:

TakeWhile[list, Count[Append[{}, #], 2] <= 3 &]

But I just get {}.

$\endgroup$
9
  • $\begingroup$ I don't have Mathematica 10.1, so I can't test this, but does the following work? First@SequenceCases[list, {Shortest[___], 2, 2}]. $\endgroup$
    – march
    Mar 1, 2017 at 5:22
  • 1
    $\begingroup$ @march Actually not,but First[SequenceCases[ list, {Except[2] ..., 2, Except[2] ..., 2, Except[2] ..., 2}]] work for my case,Thanks. :) $\endgroup$
    – yode
    Mar 1, 2017 at 5:30
  • $\begingroup$ It might be worth noting that your attempt and the accepted answer will take everything before the fourth 2. In your example that's identical but for {1,2,1,2,1,2,1,2} you'd get {1,2,1,2,1,2,1}. Is that your intention? $\endgroup$ Mar 1, 2017 at 9:01
  • $\begingroup$ @MartinEnder Oh,god.You give me a big remind that I have made a mistake.Actually,I want to get {1,2,1,2,1,2} in your case. $\endgroup$
    – yode
    Mar 1, 2017 at 9:07
  • 1
    $\begingroup$ Also lst[[;;Position[lst,2][[3,1]]]] $\endgroup$
    – user1066
    Apr 26, 2023 at 5:35

9 Answers 9

11
$\begingroup$

Perhaps:

i = 1; While[Count[list[[1 ;; i]], 2] < 3, i++]
list[[1 ;; i]]

or

list[[1 ;; Catenate[Position[list, 2]][[3]]]]
$\endgroup$
4
  • $\begingroup$ Look little consice,i=0;While[Count[list[[1;;++i]],2]<3];list[[;;i]].And do you know why my TakeWhile don't work? $\endgroup$
    – yode
    Mar 1, 2017 at 5:04
  • $\begingroup$ TakeWhile tests each element not the cumulative list. You could do something ugly like: list[[1 ;; Length@TakeWhile[ Count[list[[1 ;; #]], 2] & /@ Range[Length[list]], # < 3 &] + 1]] though I am sure others would have better ways $\endgroup$
    – ubpdqn
    Mar 1, 2017 at 5:14
  • $\begingroup$ Yep,I know that.So I give a Append to collect it. $\endgroup$
    – yode
    Mar 1, 2017 at 5:16
  • $\begingroup$ @yode but your append is in your test $\endgroup$
    – ubpdqn
    Mar 1, 2017 at 5:17
8
$\begingroup$

I think you meant to do this:

Module[{tmp = {}}, TakeWhile[list, Count[AppendTo[tmp, #], 2] <= 3 &]]
$\endgroup$
4
  • $\begingroup$ Thanks,I have adjust that ==.But since AppendTo can work,why Append not?Confusing still. $\endgroup$
    – yode
    Mar 1, 2017 at 5:25
  • $\begingroup$ Because you are always appending to {} whereas I am appending to tmp, which is hence a growing list. In my case, tmp contains all the elements processed so far. In your case, it's just the same as {#}, i.e., just the current element wrapped in {} $\endgroup$
    – Felix
    Mar 1, 2017 at 5:27
  • $\begingroup$ Oh,I see now.Thanks very much. $\endgroup$
    – yode
    Mar 1, 2017 at 5:31
  • $\begingroup$ @Felix nicely instructive $\endgroup$
    – ubpdqn
    Mar 1, 2017 at 5:50
6
$\begingroup$

Using PositionIndex:

Take[list, Check[PositionIndex[list][2][[3]], 1 ;; -1]]

Check will substitute specs to get the entire list 1;;-1, should the PositionIndex command fail.

{3, 1, 3, 1, 2, 1, 2, 2}

$\endgroup$
1
  • 1
    $\begingroup$ (+1) Nice use for Check! $\endgroup$ Apr 25, 2023 at 14:42
5
$\begingroup$

As of 10.1 we can also do this:

list[[;; First@First@SequencePosition[list, {2, 2, 2}]]]

Or to generalize:

takeBefore[list_,obj_,reps_]:=
  list[[;; First@First@SequencePosition[list, ConstantArray[obj,reps]]]]

Of course that assumes the sublist is in there. If it's not the First calls will whine at you:

In[11]:= SeedRandom[3]
list = RandomChoice[{.2, .5, .3} -> {1, 2, 3}, 20]

Out[12]= {2, 1, 2, 1, 1, 2, 2, 3, 2, 3, 3, 2, 1, 3, 3, 1, 2, 1, 2, 2}

In[13]:= list[[;; First@First@SequencePosition[list, {2, 2, 2}]]]
$\endgroup$
5
$\begingroup$
Block[{i = 1}, NestWhileList[list[[i++]] &, Nothing, (Count[{##}, 2] < 3) &, All ]]

{3, 1, 3, 1, 2, 1, 2, 2}

$\endgroup$
5
$\begingroup$

We can define an operator f[v, k, m] that splits an input list every time the number of vs reaches k, and use the optional third argument m to get desired part(s):

ClearAll[f]
f[v_, k_, m_ : 1] := Module[{s = 0}, 
  Split[#, Or[(s += Boole[# == v]) < k, s = 0] &][[m]]] &

Examples:

f[2, 3] @ list /. 2 -> Highlighted[2]

enter image description here

f[2, 3, All] @ list /. 2 -> Highlighted[2]

>     {{3, 1, 3, 1, 2, 1, 2, 2}, {2, 3, 2, 3, 2}, {2, 3, 3, 3, 2, 2}, {2}}

f[2, 6] @ list /. 2 -> Highlighted[2]

>     {3, 1, 3, 1, 2, 1, 2, 2, 2, 3, 2, 3, 2}

$\endgroup$
4
$\begingroup$

Another way using Partition:

Last[
    Map[Function @ If[SameQ[Count[#, 2], 3], #, Nothing],
        Apply[Join,
            Map[Function @ Partition[list, {#}], Range @ Length @list]
        ]
    ]
 ]

(*{3,1,3,1,2,1,2,2}*)

The following form is courtesy of @Syed (Thanks, mate!):

list /. 
{k : Except[2] ...,h : OrderlessPatternSequence[___, 2, 2, 2, ___], ___} :> {k, h}

(*{3,1,3,1,2,1,2,2}*)
$\endgroup$
3
  • 1
    $\begingroup$ You are looking for the first consecutive occurrence of 2. The task is to grab enough of the list such that three 2s are included. $\endgroup$
    – Syed
    Apr 25, 2023 at 15:02
  • $\begingroup$ You're right, I will think hard to improve my answer. $\endgroup$ Apr 25, 2023 at 15:06
  • 1
    $\begingroup$ list /. {k : Except[2] ..., h : OrderlessPatternSequence[___, 2, 2, 2, ___], ___} :> {k, h} $\endgroup$
    – Syed
    Apr 25, 2023 at 15:22
4
$\begingroup$
list = {3, 1, 3, 1, 2, 1, 2, 2, 2, 3, 2, 3, 2, 2, 3, 3, 3, 2, 2, 2};

First @ SequenceCases[list, _?(Count[#, 2] == 3 &)]

{3, 1, 3, 1, 2, 1, 2, 2}

$\endgroup$
2
$\begingroup$

yet another Sow and Reap

index = 1;

x = 0;

arr = {3, 1, 3, 1, 2, 1, 2, 2, 2, 3, 2, 3, 2, 2, 3, 3, 3, 2, 2, 2};

While[
    x <= 3
    ,
    Sow[arr[[index]]];
    index++;
    If[arr[[index]] == 2,
        x++
    ];
] //
Reap //
Last //
First
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.