6
$\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$
  • 1
    $\begingroup$ You may need to use the variant form Map[Function[{x},...,First[#]==x&]]],...]. $\endgroup$ – Daniel Lichtblau Dec 6 '13 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$ – 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
  • 3
    $\begingroup$ Possibly duplicate (16947). $\endgroup$ – Silvia Dec 7 '13 at 4:26
7
$\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]]
| improve this answer | |
$\endgroup$
  • 1
    $\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 at 20:22
7
$\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

| improve this answer | |
$\endgroup$
6
$\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 :)

| improve this answer | |
$\endgroup$
  • $\begingroup$ This is a nice use case I for one had not anticipated. $\endgroup$ – Daniel Lichtblau Apr 27 '19 at 13:05
3
$\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.

| improve this answer | |
$\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.