9
$\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$
4
  • 1
    $\begingroup$ You may need to use the variant form Map[Function[{x},...,First[#]==x&]]],...]. $\endgroup$ Dec 6, 2013 at 22:29
  • 3
    $\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$ Dec 6, 2013 at 22:31
  • 2
    $\begingroup$ The name is not virtual function but Pure Function in a Mathematica context. $\endgroup$ Dec 6, 2013 at 23:41
  • 3
    $\begingroup$ Possibly duplicate (16947). $\endgroup$
    – Silvia
    Dec 7, 2013 at 4:26

4 Answers 4

9
$\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$
1
  • 5
    $\begingroup$ Just a nit to pick since I think someone unused to Mathematica might get confused, I think it’d be better to say that “the parameter # in the outer function gets overwritten in the inner function # and so it needs to be bound to a different name either via Function[x, ...] or With[{x=#}, ...]”. $\endgroup$
    – b3m2a1
    Mar 16, 2020 at 20:22
11
$\begingroup$

Using Curry or OperatorApplied

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 &.

Update for version 12.1

In version 12.1, OperatorApplied is the new name for Curry. The documentation for Curry states that it is now being phased out.

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$
1
  • $\begingroup$ This is a nice use case I for one had not anticipated. $\endgroup$ Apr 27, 2019 at 13:05
8
$\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$
5
$\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 and acknowledge that you have read and understand our privacy policy and code of conduct.

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