# How do I find the elements in a list that return the highest value for a function?

Suppose we have a list of values and a function f. I want to find which of the elements maximizes the return value of the function in Mathematica. Let call the function ListMaxArg. On the following example,

ListMaxArg[Total, {{1, 2, 3}, {10}}]


it should return {10}. Is there any such function in Mathematica's library? If not, what is the simplest way to write it? I can for sure write the function using a loop, but I am looking for something more functional style.

## migrated from math.stackexchange.comFeb 23 '12 at 1:57

This question came from our site for people studying math at any level and professionals in related fields.

• – Mr.Wizard Feb 23 '12 at 2:09
• @Mr.Wizard Yes, this question is a generalization of '1342'. – Brett Champion Feb 23 '12 at 5:01

While using Ordering as in Mr.Wizard's answer will most likely be the fastest non-compiled solution, it will not return all possible arguments that maximize the return value. Here's a simple way of writing a function that does this:

listMaxArg[f_, list_] := With[{max = f /@ list // Max}, Select[list, f@# == max &]]


Here's an example that compares the two solutions:

a = {{1, 2, 3}, {10}, {6, 4}};
listMaxArg[Total, a]
(* Out[1]= {{10}, {6, 4}} *)

listMaxArgMrWiz[Total, a]
(*Out[2]= {{6, 4}} *)

• +1. Note that Pick will be faster than Select here, about twice faster for really long lists. – Leonid Shifrin Feb 23 '12 at 11:43
• @LeonidShifrin Thanks. I did remember that Pick should be faster than Select, and tried listMaxArgPick[f_, list_] := Pick[list, Unitize[##/Max[##] &@(f /@ list), 1], 1]. Unfortunately, this unpacks, which slows it down, so I put it aside to poke at later. Can you point me to what I'm doing incorrectly (or how that can be written better)? I generated a random list with l = Table[RandomInteger[5, RandomInteger[{1, 5}]], {100000}]; – rm -rf Feb 23 '12 at 12:48
• Pick has an optional third parameter, which allows to specify which element you want to be picked. The code I have is thus: listMaxArgAlt[f_, lst_] := Pick[lst, #, Max[#]] &[f /@ lst], and it is about twice faster, since I don't have to play games with Unitize. – Leonid Shifrin Feb 23 '12 at 12:57
• It should be noted that Pick unpacks in version 7. – Mr.Wizard Feb 23 '12 at 13:29
• Interestingly, Select does not unpack, because for each element, Total applied to it, does not unpack. Still, it is slower than Pick here, because of the overhead of extra invocation of Function[f@#==max] (symbolic overhead). Pick has to unpack because it performs structural comparison (based on internal equivalent of SameQ actually, not Equal). This situation is similar to that in this question. This is an interesting and didactic example IMO, this present one. – Leonid Shifrin Feb 23 '12 at 14:30

## Update 2017

Mathematica 10 introduced MaximalBy, becoming the canonical method.

MaximalBy[{{1, 2, 3}, {10}, {6, 2}, {3, 7}}, Total]

{{10}, {3, 7}}


It is fast as shown in the updated timings below.

If I understand the question this should be fastest:

listMaxArg[f_, L_List] := L ~Extract~ Ordering[f /@ L, -1]

listMaxArg[Total, {{1, 2, 3}, {10}}]

{10}


You could also find the top n values by using -n as the second argument to Ordering.
This could be included in the function, e.g. listMaxArg[f_, L_List, n_Integer] := . . .

This method should be fast for finding multiple maximum values:

listMaxArg[f_, L_List] := L ~Extract~ Position[#, Max@#] &[f /@ L]

listMaxArg[Total, {{1, 2, 3}, {10}, {6, 2}, {3, 7}}]

{{10}, {3, 7}}


I argue the superiority of the Extract-Position method (from Arnoud Buzing) over Select on the basis of timings. I will use Tr in the place of Total as it is faster on Packed Arrays, and therefore better shows the overhead of each method.

listMaxArgRM[f_, list_] :=
With[{max = f /@ list // Max}, Select[list, f@# == max &]]

listMaxArgMrW[f_, L_List] :=
L ~Extract~ Position[#, Max@#] &[f /@ L]

SeedRandom[1]
list = RandomInteger[7, #] & /@ RandomInteger[{1, 5}, 1000000];

r1 = listMaxArgRM[Tr, list];  // RepeatedTiming
r2 = listMaxArgMrW[Tr, list]; // RepeatedTiming
r3 = MaximalBy[list, Tr];     // RepeatedTiming
r1 === r2 === r3

{0.77, Null}

{0.219, Null}

{0.191, Null}

True