8

Apolgies if this has been asked and answered, but I'm not even sure what to search for. I have two functions defined as follows:

F[n_]:=Max[Select[Divisors[n],#<=Sqrt[n]&]];
P[n_] := Select[Range[1, 1000], F[#] == n &];

I have two questions:

  1. I have read the Mathematica help page on the # symbol, and I think I understand most of that. I do not, however, understand what # and & do in this specific context.

  2. How can I write P[n_ ] using a single line of code? It doesn't work if I simply copy and paste the definition for F into the definition of P:

    P[n_] := Select[ Range[1, 1000], Max[Select[Divisors[n],#<=Sqrt[n]&]] == n &]
    
Ashton Baker
  • 183
  • 5

2 Answers2

12

Answering your second question - you don't maintain a proper nesting / variable localization. Here are two correct ways (there are more):

P[n_] := 
  Select[
     Range[1, 1000], 
     With[{m = #}, Max[Select[Divisors[m], # <= Sqrt[m] &]]] == n &
  ]

and

P[n_] := 
  Select[Range[1, 1000], 
     Function[m, Max[Select[Divisors[m], # <= Sqrt[m] &]] == n]]

The reason that we had to introduce an additional symbol m is that you have a function # <= Sqrt[m] & which mixes the two local variables at different levels. When this happens, you can't solve the problem using only slot-based functions, due to the apparent collision of essentially different variables.

Perhaps, the fact that you denote the argument for your original functions as n in both cases was what led to the conclusion. As a side note, avoid starting your function names with capital letters, this may lead to collisions with system symbols.

I believe that there is already an answer for the general slot-nesting question somewhere here on SE, so this answer likely has a temporary status.

Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420
5

In theory you can use only slot-based functions:

P1[n_] := Select[Range[1, 1000], Max@Select[Divisors[#], 
   Function @@ {Identity[Slot][] <= Sqrt[#]}] == n &];

P2[n_] := Select[Range[1, 1000], 
  Max@Select[Divisors[#3], #1[#2[] <= Sqrt[#3]]] == n &[Function, Slot, #] &];

You can even use the slot instead of n:

P3 = Select[Range[1, 1000], #1[Max@Select[
  Divisors[#3], #1[#2[] <= Sqrt[#3]]] == #4 &[#1, #2, #2[], #3]]] &[Function, Slot, #] &;

P[10] == P1[10] == P2[10] == P3[10]

True

Surely it is a very complicated approach, which is inappropriate for practical use. It is just an answer to Leonid's "you can't solve the problem using only slot-based functions".

ybeltukov
  • 43,673
  • 5
  • 108
  • 212
  • Excellent answer, thank you. I tried about a thousand different ways of using only slot-based functions, but I would never have come up with anything close to this. – Ashton Baker Nov 03 '13 at 22:57
  • +1. So, you solve the collision problem by delaying the binding, constructing the inner function at runtime. I haven't thought of that, pretty clever. OTOH, my statement was concerning the most straight-forward way. If you think of it, my first method (using With) is akin yours. – Leonid Shifrin Nov 04 '13 at 00:08