1
$\begingroup$

The code

Print[Select[{1, 4, 3, 9}, Mod[#, 3] == 0 &]];
Print[Select[{1, 4, 3, 9}, Mod[#, 3] == 1 &]];
Print[Select[{1, 4, 3, 9}, Mod[#, 3] == 2 &]]

gives {3,9}, {1,4} and {}, as expected. But the code

Map[Select[{1, 4, 3, 9}, Mod[#, 3] == ## &] &, {0, 1, 2}]

gives {{1}, {1}, {1}}, rather than {{3, 9}, {1, 4}, {}}, which is what I want.

What I am doing wrong? Is there a better way to achieve the same result than by using Select?

$\endgroup$
4
$\begingroup$

The problem with your attempt is that both # and ## in your expression are interpreted as both being arguments to the pure function that you're feeding as the second argument to Select. To nest Functions like this, you have to take one of them and use the non-short-hand version:

Map[Select[{1, 4, 3, 9}, Function[{x}, Mod[x, 3] == #]] &, {0, 1, 2}]

More cleanly, I would just use Table:

Table[Select[{1, 4, 3, 9}, Mod[#, 3] == k &], {k, {0, 1, 2}}]

But really, in this case, I think it's better to use Cases or Pick, because you can select the elements using Patterns rather than truth-value Functions, reserving the pure function for the Mapping over {0, 1, 2}:

Cases[{1, 4, 3, 9}, a_ /; Mod[a, 3] == #] & /@ {0, 1, 2}
Pick[{1, 4, 3, 9}, Mod[{1, 4, 3, 9}, 3], #] & /@ {0, 1, 2}

To elaborate on why the version in the OP doesn't work, we can note that their code is essentially equivalent to

Map[Select[{1, 4, 3, 9}, Function[{x}, Mod[x, 3] == x]] &, {0, 1, 2}]

In other words, in each case, the elements of {0, 1, 2} are irrelevant, and the function is just checking if Mod[x, 3] == x is True for each of {1, 4, 3, 9}, and 1 is the only one that works.

$\endgroup$
2
$\begingroup$
Outer[If[Mod[#2, 3] == #1, #2, ## &[]] &, {0, 1, 2}, {1, 4, 3, 9}]
(* {{3, 9}, {1, 4}, {}} *)

or more "sophisticated"

Pick@@Transpose[ Outer[{#2, #1 == Mod[#2, 3]} &, {0,1,2}, {1,4,3,9}], {2,3,1}]

(* {{3, 9}, {1, 4}, {}} *)
$\endgroup$
2
$\begingroup$

Another approach is to use Association and GroupBy (under Mathematica v10), so that each element is tested only once. If you can accept a different structure for the output:

GroupBy[{1, 4, 3, 9}, Mod[#, 3] &]

<|1 -> {1, 4}, 0 -> {3, 9}|>

But also preserving your structure is not difficult:

Lookup[GroupBy[{1, 4, 3, 9}, Mod[#, 3] &], Range[0, 3-1], {}]

{{3, 9}, {1, 4}, {}}


You can also use this trick

Select[{1, 4, 3, 9}, Function @@ {#}] & /@ (Mod[Slot @@ {1}, 3] == # & /@ {0, 1, 2})

{{3, 9}, {1, 4}, {}}


If you need often this construct, you can also define your own helper's crit as in

equalToMod[m_][n_][k_] := Mod[k, m] == n
Select[{1, 4, 3, 9}, #] & /@ equalToMod[3] /@ {0, 1, 2}
$\endgroup$
2
$\begingroup$

Using map and select causes all elements of {1, 4, 3, 9} to be tested 3 times rather than 1:

n = 3;
SortBy[GatherBy[Join[{1, 4, 3, 9}, Range[0, n - 1]],
         Mod[#, n] &], Mod[First[#], n] &][[All, ;; -2]]

Edit: This is probably better:

n = 3; L = {1, 4, 3, 9};
Lookup[Map[L[[#]] &, PositionIndex[Mod[L, n]]], Range[0, n - 1], {}]
$\endgroup$
  • $\begingroup$ That is fantastic, Coolwater ! My first attempt had a Do loop, which tested the elements of the big list 3 times instead of once. My first attempts at improving the code were aimed at exactly this problem. $\endgroup$ – Simon Mar 5 '16 at 12:42
  • $\begingroup$ Your edit with Lookup and PositionIndex returns {{3, 4}, {1, 2}, {}}... $\endgroup$ – unlikely Mar 5 '16 at 20:56

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