9

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?

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
Tyler Durden
  • 4,090
  • 14
  • 43

4 Answers4

11

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 :)

WReach
  • 68,832
  • 4
  • 164
  • 269
9

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]]
C. E.
  • 70,533
  • 6
  • 140
  • 264
  • 5
    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=#}, ...]”. – b3m2a1 Mar 16 '20 at 20:22
8

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

Kuba
  • 136,707
  • 13
  • 279
  • 740
Mathfan
  • 81
  • 2
5

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.

Kuba
  • 136,707
  • 13
  • 279
  • 740