1
$\begingroup$

Suppose I want to efficiently maximize an arbitrary function f over a list of argument values. (E.g. maximize the Sin[x] over the possible x-values {1., 2., 3., 4.}) and find the index of that maximum value. This is the easiest way I could think of to do it:

maxVal[f_, vals_] := Block[{fvals = f /@ vals},
vals[[Position[fvals, Max[fvals]][[1, 1]]]]
]

For example, maxVal[Sin, {1., 2., 3., 4.}] returns 2..

(Note that the expression Position[fvals, Max[fvals]][[1, 1]] above is equivalent to the simpler expression Sort[fvals][[1]], but I believe that the latter expression is slower to calculate because it needs to sort the entire list instead of just keeping track of its lowest value.)

This seems very cumbersome to me - is there an easier way to do it using built-in Mathematica functions?

$\endgroup$

closed as off-topic by m_goldberg, MarcoB, Itai Seggev, garej, LCarvalho Jul 31 '17 at 18:34

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "This question arises due to a simple mistake such as a trivial syntax error, incorrect capitalization, spelling mistake, or other typographical error and is unlikely to help any future visitors, or else it is easily found in the documentation." – m_goldberg, MarcoB, Itai Seggev, garej, LCarvalho
If this question can be reworded to fit the rules in the help center, please edit the question.

  • 3
    $\begingroup$ Have you seen MaximalBy[]? $\endgroup$ – J. M. is away Jul 28 '17 at 2:06
  • 1
    $\begingroup$ Have you checked out Ordering? $\endgroup$ – Carl Woll Jul 28 '17 at 2:26
  • 1
    $\begingroup$ @CarlWoll I believe that Ordering is inefficient for the same reason as Sort. $\endgroup$ – tparker Jul 28 '17 at 2:29
  • 5
    $\begingroup$ Look at the 2 arg form, e.g. Ordering[values, -1] $\endgroup$ – Carl Woll Jul 28 '17 at 2:30
  • 2
    $\begingroup$ As Carl says, the two-argument form of Ordering[] is what you want here. $\endgroup$ – J. M. is away Jul 28 '17 at 4:27
0
$\begingroup$

Answer

maxVal[f_, vals_] := Ordering[Thread[f[vals]], {-1}]

Performance

First@RepeatedTiming[maxVal[Sin, RandomReal[{-9, 9}, 10^7]]]
0.838
ListPlot[
 Table[
  {10^n, First@RepeatedTiming[maxVal[Sin, RandomReal[{-9, 9}, 10^n]]]}
  , {n, 1, 8}
  ]
 , ScalingFunctions -> {"Log", "Log"}
 , PlotTheme -> "Scientific"
 , FrameLabel -> {"List Length", "Time [s]"}
 ]

Mathematica graphics

$\endgroup$
0
$\begingroup$

Based on J.M. and Carl Woll's helpful comments, it seems that the quickest way to find the maximum value is MaximalBy[vals, f] and the quickest way to find its index is Ordering[f/@vals, -1][[1]].

By the way, I ran

rands = RandomReal[1, 10^7];
Timing[ord = Ordering[rands]; ord[[1]]]
Timing[Ordering[rands, 1][[1]]]

and verified that the two-argument form of Ordering is indeed far more efficient that just taking the first element of the one-argument form - the two-argument form doesn't sort the entire list, but only as much of the list as is needed.

$\endgroup$

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