7
$\begingroup$

I'm new to use the amazing map function in Mathematica, and I've found it really elegant to program in simple lines of code. However, I'd like to perform more elegant stuff. I've found this question, but its not what I'm trying to achieve. How do I use Map for a function with two arguments?

I want to apply a two, or more, argument function using columns of a list as arguments

My approach is the following:

For an arbitrary list:

vector = Table[   {RandomReal[], RandomReal[], RandomReal[]}, {n, 0, 10} ]

enter image description here

I want to apply the Tan[] using two columns as an arguments, so I tried unsuccessfully writing:

Tan[#1/#2] & {vector[[;; , {1, 2}]]}

enter image description here

I know I can use Table[] (in a for loop way) like this to achieve my solution:

Table[{ Tan[vector[[n, 2]]/vector[[n, 1]]]}, {n, 1, Length[vector]}] 

enter image description here

However, I'd like to master the functional programming style. How can I achieve the same output using Map(/@)

Any tutorial/book/lecture would be greatly appreciated as well.

Thanks!

$\endgroup$
2
  • 2
    $\begingroup$ Tan[#1/#2] & @@@ vector[[;; , {1, 2}]] would do it; see manual: @@@ means "apply at level 1". Alternatively, Tan[#[[1]]/#[[2]]] & /@ vector. Maybe invert #[[1]] and #[[2]] – I'm unsure as to which one you want. $\endgroup$
    – Roman
    Commented Apr 5, 2022 at 16:30
  • 1
    $\begingroup$ Also Tan[vector[[All,2]]/vector[[All,1]]] $\endgroup$
    – user1066
    Commented Apr 5, 2022 at 21:21

4 Answers 4

14
$\begingroup$

Since you're looking to learn more about functional style, I'll elaborate rather than just provide an answer.

We start with our table:

vector = Table[{RandomReal[], RandomReal[], RandomReal[]}, {n, 0, 10}]

We could either re-structure the table first, or deal with selecting which elements to apply the Tan function to later. If we restructure first, I'd actually prefer the following to what you had (vector2 is there just so I can easily refer to this later).

vector2 = vector[[All, 1 ;; 2]]

Now, let's consider several ways to map. It's often easier to get a feel for these things by using undefined symbols in your mapping expression. So, compare what you get with these:

f /@ vector
(*gives something like {f[{0.408218, 0.315962, 0.472218}], ...}*)

f /@ vector2
(*gives something like {f[{0.408218, 0.315962}], ...}*)

f @@@ vector
(*{f[0.408218, 0.315962, 0.472218], ...}*)

f @@@ vector2
(*{f[0.408218, 0.315962]}*)

Map[f, vector, {-2}]
(*{f[{0.408218, 0.315962, 0.472218}]}*)

etc

That last form for Map is nice when it's easier to figure out where to apply a function from the "bottom" up in a structure, but in this case it's equivalent to one of the previous forms, because your structure isn't very deep.

Let's pick this expression: f @@@ vector2. At this point, you could define your anonymous function like you did: Tan[#1/#2] &, to give this:

Tan[#1/#2] & @@@ vector2

(*or alternatively, since vector2 was just convenience:*)
Tan[#1/#2] & @@@ vector[[All, 1 ;; 2]]

But, another nice thing that is often seen in a functional style is function composition. Since we already have the functions you need, specifically Divide and Tan, you don't need the Slot version. You could just do this:

Tan@*Divide @@@ vector[[All, 1 ;; 2]]

I'm not suggestion that this is better. Sometimes it's clearer/cleaner.

Now, if we had chosen this to start: f /@ vector, then we would need to use Part to extract the elements from the list:

Tan[#[[1]]/#[[2]]] & /@ vector
$\endgroup$
2
  • $\begingroup$ Excellent mini-tutorial. Do you have any suggestion of literature to further learn Mathematica? Amazing! $\endgroup$ Commented Apr 28, 2022 at 17:39
  • 1
    $\begingroup$ @JoshuaSalazar Maybe you would be interested in the two first links of this answer and also this question and this question $\endgroup$ Commented Aug 6, 2022 at 3:08
5
$\begingroup$

One way would be to use Inner:

Inner[Times,vector,{1,1,1},Tan[#2/#1]&]


(* {0.328928, 0.0877953, -1.11698, 0.163536, 8.47242, -1.30076, -0.876783, -0.445995, 

    3.10856, 13.781, -0.0637223} *)

To join the result to vector, creating a new column:

result=Join[vector,Transpose[{Inner[Times,vector,{1,1,1},Tan[#2/#1]&]}],2]

$$\left( \begin{array}{cccc} 0.923193 & 0.293373 & 0.28368 & 0.328928 \\ 0.563943 & 0.0493849 & 0.29899 & 0.0877953 \\ 0.0540691 & 0.464139 & 0.238681 & -1.11698 \\ 0.965447 & 0.1565 & 0.083503 & 0.163536 \\ 0.139205 & 0.639633 & 0.73339 & 8.47242 \\ 0.291075 & 0.647993 & 0.45214 & -1.30076 \\ 0.157494 & 0.381412 & 0.516915 & -0.876783 \\ 0.15384 & 0.418765 & 0.603784 & -0.445995 \\ 0.682685 & 0.859883 & 0.08333 & 3.10856 \\ 0.523494 & 0.784382 & 0.919915 & 13.781 \\ 0.0527971 & 0.991843 & 0.757848 & -0.0637223 \\ \end{array} \right)$$

where:

vector = Table[{RandomReal[], RandomReal[], RandomReal[]}, {n, 0, 10}]

$$\left( \begin{array}{ccc} 0.923193 & 0.293373 & 0.28368 \\ 0.563943 & 0.0493849 & 0.29899 \\ 0.0540691 & 0.464139 & 0.238681 \\ 0.965447 & 0.1565 & 0.083503 \\ 0.139205 & 0.639633 & 0.73339 \\ 0.291075 & 0.647993 & 0.45214 \\ 0.157494 & 0.381412 & 0.516915 \\ 0.15384 & 0.418765 & 0.603784 \\ 0.682685 & 0.859883 & 0.08333 \\ 0.523494 & 0.784382 & 0.919915 \\ 0.0527971 & 0.991843 & 0.757848 \\ \end{array} \right)$$

$\endgroup$
2
$\begingroup$
SeedRandom[0];

m = RandomReal[{0, 1}, {10, 3}];

Using ArrayReduce (new in 12.2)

ArrayReduce[Tan @* Divide @@ # &, Most /@ m, 2]

{1.66766, 0.692379, 0.392478, 1.27323, 6.25057, 1.16759, 32.3583, 1.99305, 1.40604, 0.773145}

The above result agrees with the accepted answer.

$\endgroup$
1
  • 1
    $\begingroup$ +1 Very nice answer, @eldo! $\endgroup$ Commented Jun 25 at 21:40
1
$\begingroup$
SeedRandom[0];

m = RandomReal[{0, 1}, {10, 3}];

Using Replace at level 1:

Replace[m, x_ :> Tan@*Divide @@ Most@x, 1]

{1.66766,0.692379,0.392478,1.27323,6.25057,1.16759,32.3583,1.99305,1.40604, 0.773145}

$\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.