30
$\begingroup$

I have the following working construction:

Select[ln125, # == Nearest[ln125, 551.748][[1]] &]

Here, ln125 is a one dimensional list.

What I want further is to apply this construction not only to ln125, for example, but for a list of {ln125,ln126,ln127}.

Let's say,

f[list_]:=Select[list, # == Nearest[list, 551.748][[1]] &]

I want to do this:

f /@ {ln125,ln126,ln127}.

The question is: is it possible to acheive my goal only using pure functions? That is, without defining dummy function (f in my case)? The problem is that definition of f already has pure function (as a criteria for Select) and, thus, there should be two pure function of different depths (don't know how to name it correctly) at once. In other words, I want to turn the list variable into # but in a way that Mathematica can distinguish which # goes with each different pure function.

$\endgroup$
1
  • 3
    $\begingroup$ Yes if you use the full form Function. $\endgroup$ Dec 26, 2012 at 1:48

5 Answers 5

18
$\begingroup$

In can be done in a terse way with nested pure functions:

lists = RandomReal[{0, 10}, {3, 10}]

{{3.35338, 2.82572, 0.152277, 1.19036, 9.88211, 6.55398, 8.11855, 0.793288, 9.04547, 6.42518}, {4.95417, 7.73982, 5.58323, 3.09912, 5.44546, 8.88474, 2.67437, 8.20605, 4.55918, 1.95303}, {2.53793, 6.67839, 8.71033, 8.4877, 0.634367, 7.99796, 4.74131, 0.679337, 8.29468, 9.91209}}

Select[#, With[{aList = #}, # == Nearest[aList, 5.][[1]] &]] & /@ lists

{{6.42518}, {4.95417}, {4.74131}

Using With to insert expressions into Function, which has the HoldAll attribute, is trick that is useful to keep in mind.

$\endgroup$
15
$\begingroup$

You can use the form Function[{x,y,z}, body] to define a pure function with formal parameters x,y,z ( see Documentation >> Function)

Let

 lists = {ln125, ln126, ln127} = RandomReal[{0, 10}, {3, 10}]
 (* {{1.72286, 5.24912, 8.87257, 5.77593, 6.31276, 1.77914, 2.06393,
      0.328725, 9.46436, 4.96257}, 
     {1.71171, 2.54337, 5.93807, 9.46774,  6.99601, 2.76927, 7.58995,
      1.25785, 2.09789, 9.32326}, 
     {6.9821, 8.62002, 2.0763, 8.9402, 4.36728, 3.8571, 4.4175,
      7.15698, 7.64633, 5.23772}} *)

Define, (with 4. playing the role of 551.748 in your example):

 f2 = Function[{x}, Select[x, # == Nearest[x, 4.][[1]] &]]
 f2 /@ lists
 (* {{4.96257}, {2.76927}, {3.8571}} *)   

or

  f3 = With[{temp = Nearest[#1, 4.`][[1]]}, Select[#1, # == temp &]] &
  f3 /@ lists
  (* {{4.96257}, {2.76927}, {3.8571}} *)   
$\endgroup$
9
$\begingroup$

To clarify one of the answers. Note there is no way to distinguish both # inside # == Nearest[#, 551.748][[1]] in

Select[#, # == Nearest[#, 551.748][[1]] &] &

as you already noted. So, you need to give the outermost # a name and Function[...] is just for that. This one works:

Function[{l}, Select[l, # == First[Nearest[l, 551.748]] &]]

Personally, I don't like the With trick above: if you need to give it a name, use the language construct for that. Then you do:

Function[{l}, Select[l, # == First[Nearest[l, 551.748]] &]] /@ {ln125,ln126,ln127}

Note that a Function[...] is already a (...&), so you don't need the usual ...& /@..., just Function[...] /@.

P.S If you do this often, this is, fix a value (i.e. First[Nearest[l, 551.748]]) inside another function of two or more parameters (i.e. Equal in your case) to have a function of the free parameters, then the following can be useful

FixCurry[f_, v_] := f[v, ##] &;

So, FixCurry[Equal, 3] is Equal[3,#] &. And this can be used in your case like

Select[#, FixCurry[Equal, First[Nearest[#, 5.]]]] & /@ {ln125,ln126,ln127}

which avoids the inner (..&) via the FixCurry construct. If you wonder how this could be used in other contexts, notice that the first argument to FixCurry can be a pure function with the (...&) syntax. In your example, more verbose but equivalent,

Select[#, FixCurry[#1 == #2 &, First[Nearest[#, 5.]]]] & /@ {ln125,ln126,ln127}

Hope it helps.

$\endgroup$
1
$\begingroup$

The "working construction" Select[list, # == Nearest[list, value][[1]] &] will give a list of the form {nearestvalue, nearestvalue, ...}, in which the nearest value is simply repeated the number of times it appears in list.

If lists contains several lists and all you want is the value in each list that is nearest to value then

nearestvals = Nearest[#, value][[1]]& /@ lists

will give you a list of those values. If you also want the repeat counts then

MapThread[{#2, Count@##}&, {lists, nearestvals}]

will give {{nearestvalue, count}, {nearestvalue, count}, ...}, with a pair for each list in lists.

$\endgroup$
1
  • 1
    $\begingroup$ Best answer. A NearestFunction already returns those list elements which are the nearest to a given value. Wrapping a Select around a NearestFunction to select the whole NearesFunction output is not particularly clever. $\endgroup$
    – Fortsaint
    Sep 6, 2017 at 0:03
1
$\begingroup$

You may use NearestTo with Composition.

With

SeedRandom[123]
{ln125, ln126, ln127} = RandomReal[{500, 600}, {3, 10}];

Then

First@*NearestTo[551.748] /@ {ln125, ln126, ln127}
{546.671, 562.827, 549.18}

or without First if you want the nested list.

NearestTo[551.748] /@ {ln125, ln126, ln127}
{{546.671}, {562.827}, {549.18}}

Hope this helps.

$\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.