7
$\begingroup$

I wanted to know the most efficient and less resource consuming way to do the following: first, use the Select function to filter some values out of some list, e.g.

a={1,2,3,4,5,6};
a2=Select[a,EvenQ];

Now, let's create another list of the same length, b={a,b,c,d,e,f}. I want to pick exactly the same elements that I picked in a, i.e. b2={b,d,f}. Is there a built-in function that allows me to do that? If not, what would be the quickest way to do that (in terms of computing time)?

Edit: after some useful responses, I want to clarify something: I still want to do the selection in list a, i.e. I want to know if there is a way to do the selection in both lists a,b in one single step. What I've thought of is combining both lists with c=Transpose[{a,b}] and then applying Select with the condition on c[[i,1]], where i represents the index of either aor b. However, if there is any other solution, I'd like to hear it.

$\endgroup$
0

6 Answers 6

5
$\begingroup$

An update

Using the third argument of GroupBy, PositionIndex and Extract:

Extract[GroupBy[PositionIndex[blist], EvenQ, Keys], Key[{True}]]

(*{b, d, f}*)

Or using AssociationThread, GroupBy and Lookup:

Keys@Lookup[GroupBy[AssociationThread[#, Range[Length@#]] &@blist, EvenQ], True]

(*{b, d, f}*)
$\endgroup$
8
$\begingroup$

You could use Pick[]:

Pick[{a, b, c, d, e, f}, EvenQ[{1, 2, 3, 4, 5, 6}]]
(*  {b, d, f}  *)

Timing examples (numerical methods on packed arrays are naturally fastest, but data is not always numerical and packed):

biglist = Range[10^7];
Pick[biglist, EvenQ[biglist]]; // RepeatedTiming
(*  {0.454526, Null}  *)

biglist = Developer`FromPackedArray@Range[10^7];
Pick[biglist, EvenQ[biglist]]; // RepeatedTiming
(*  {0.28087, Null}  *)

biglist = Range[10^7];
Pick[biglist, Mod[biglist, 2], 0]; // RepeatedTiming
(*  {0.076138, Null}  *)

biglist = Developer`FromPackedArray@Range[10^7];
Pick[biglist, Mod[biglist, 2], 0]; // RepeatedTiming
(*  {1.35772, Null}  *)
$\endgroup$
6
$\begingroup$

Or use Association.

Clear[list1, list2, asso, list];
list1 = {1, 2, 3, 4, 5, 6};
list2 = {a, b, c, d, e, f};
asso = Association[Thread[list2 -> list1]];
list = Select[asso, EvenQ]
Keys@list

<|b -> 2, d -> 4, f -> 6|>

{b, d, f}

$\endgroup$
5
$\begingroup$

There can be many solutions, and here is one of them.

Clear[alist, blist]
alist = {1, 2, 3, 4, 5, 6};
blist = {a, b, c, d, e, f};
Extract[blist, Position[alist, x_ /; EvenQ[x]]]

Another one could be:

Pick[blist, EvenQ[alist]]

Using Transpose:

Select[Transpose[{alist, blist}], EvenQ@First@# &][[All, -1]]

Result

{b, d, f}

$\endgroup$
3
$\begingroup$

The most minimal way -I think- to pick the even elements is to use the step specification in the Part like so:

list = {a, b, c, d, e, f};

list[[2 ;; -1 ;; 2]]

{b, d, f}

$\endgroup$
5
  • $\begingroup$ Sorry, but that's not what I asked, it was just an example. My list has various nesting levels and the conditions I want to impose are fairly complicated, but the basics are the same. $\endgroup$
    – Marcosko
    Commented Sep 11, 2022 at 12:38
  • 1
    $\begingroup$ @Marcosko "My list has various nesting levels" -- If you mean you wish to pick out elements at various levels, this will make some solutions, such as your own Select[], invalid on the actual use case. -- The limitation in this answer seems to be that the solution does not depend on the a list or the test function and assumes they are always consecutive integers and EvenQ. $\endgroup$
    – Michael E2
    Commented Sep 11, 2022 at 13:00
  • $\begingroup$ @Marcosko please see the comment by Michael E2 as well $\endgroup$
    – bmf
    Commented Sep 11, 2022 at 13:09
  • $\begingroup$ @MichaelE2 maybe I read the description of the problem too quickly, but I thought that the objective was to single out the letters that correspond to the even numbers. After your comment and reading again, indeed the suggested solution here does not generalize nicely for generic associations $\endgroup$
    – bmf
    Commented Sep 11, 2022 at 13:10
  • $\begingroup$ @MichaelE2, that's correct, for now I just want to select at the first level. My point was that the solution proposed in this post wasn't general enough to be useful for me. $\endgroup$
    – Marcosko
    Commented Sep 11, 2022 at 13:11
3
$\begingroup$

KeySelect is another possibility

al = {1, 2, 3, 4, 5, 6};
bl = {a, b, c, d, e, f};

KeySelect[EvenQ] @ Thread[al -> bl]

enter image description here

Values[%]

{b, d, f}

It should be noted that KeySelect automatically creates an Association. So we can use Thread instead of AssociationThread saving 11 keystrokes.

$\endgroup$
1
  • $\begingroup$ (+1) Nice, @eldo! $\endgroup$ Commented Dec 5, 2023 at 4:05

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.