5
$\begingroup$

I have the following working expression:

In[15]:= Length[Select[IntegerPartitions[10],First[#1]==5&]]
Out[15]= 7

But, instead of using the constant 5 I want to map all values from 1 to 10 into this function. If I nest the pure function inside another it doesn't work:

In[18]:= Map[Length[Select[IntegerPartitions[10],First[#]==#&]]&,Range[10]]
Out[18]= {0,0,0,0,0,0,0,0,0,0}

What is the way to do this?

$\endgroup$
  • $\begingroup$ You may need to use the variant form Map[Function[{x},...,First[#]==x&]]],...]. $\endgroup$ – Daniel Lichtblau Dec 6 '13 at 22:29
  • 2
    $\begingroup$ This variant seems to work. Map[ With[{a = #}, Length[Select[IntegerPartitions[10], First[#] == a &]]] &, Range[10]] Out[257]= {1, 5, 8, 9, 7, 5, 3, 2, 1, 1} $\endgroup$ – Daniel Lichtblau Dec 6 '13 at 22:31
  • 2
    $\begingroup$ The name is not virtual function but Pure Function in a Mathematica context. $\endgroup$ – Sjoerd C. de Vries Dec 6 '13 at 23:41
  • 1
    $\begingroup$ Possibly duplicate (16947). $\endgroup$ – Silvia Dec 7 '13 at 4:26
5
$\begingroup$

You can have a pure function inside a pure function even in this case, you just can't have the name of the parameter being "#" in both. This works:

Map[Function[x, 
  Length[Select[IntegerPartitions[10], First[#] == x &]]], Range[10]]
$\endgroup$
6
$\begingroup$

This is probably not going to be the best answer but offering it as an opener or as a guide to towards a better solution

Setting your initial input as a function

f[n_]:=Length[Select[IntegerPartitions[10],First[#]==n&]]

then

Map[f,Range[10]]
{1, 5, 8, 9, 7, 5, 3, 2, 1, 1}

No doubt regular contributors can improve on this

$\endgroup$
4
$\begingroup$

Using Curry

Pure function nesting is one of the use cases for Curry, introduced in version 11.3:

Length[
  Select[IntegerPartitions[10], Curry[First[#] == #2 &][#]]
] & /@ Range[10]

(* {1, 5, 8, 9, 7, 5, 3, 2, 1, 1} *)

First[#1] == #2 & defines a two argument pure function. By wrapping Curry[...][#] around this, we bind the inner slot reference #2 to the value of the outer slot reference #. After binding, we are left with a single argument function that is suitable for use with Select. For example, in one mapping iteration the outer # has the value 7 and the curried function Curry[First[#1] == #2 &][7] is essentially equivalent to First[#1] == 7 &.

Currying The Hard Way

A rather obscure idiom makes it possible to perform such currying in pure functions, even before version 11.3:

Length[
  Select[IntegerPartitions[10], #0[[0]][First[#[1]] == #2] &[Slot, #]]
] & /@ Range[10]

(* {1, 5, 8, 9, 7, 5, 3, 2, 1, 1} *)

The cryptic expression #0[[0]][First[#[1]] == #2]&[Slot, #] performs the necessary currying. #0[[0]] expands to Function. The disguised use of the symbol Function is necessary to avoid shadowing the inner slot references. #[1] expands to Slot[1], i.e. #1. #2 expands to the value of the outer #. So, if the outer # were 7, then we would get First[#1] == 7 & as desired.

This construction is likely too ugly to actually use. Thank goodness for the arrival of Curry :)

$\endgroup$
  • $\begingroup$ This is a nice use case I for one had not anticipated. $\endgroup$ – Daniel Lichtblau Apr 27 at 13:05
2
$\begingroup$

You can also perform this without "netsted functions" issue. For example:

Count[IntegerPartitions[10][[All, 1]], #] & /@ Range[10]

It could be even faster but we have to assume that you know the output of IntegerPartitions (explained on the bottom):

Reverse @ Tally[IntegerPartitions[10][[All, 1]]][[All, 2]]

Description

  • IntegerPartitions[10][[All, 1]] because only first elements are important

  • [[All, 2]] after Tally -> here we assume that we know that there will be a set of values from 1 to 10, otherwise some sort of filtering is needed.

  • Reverse because IntegerPartitions list values are decreasing.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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