Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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.

share|improve this question

migrated from math.stackexchange.com Feb 23 '12 at 1:57

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

1  
Related: mathematica.stackexchange.com/q/1342/121 –  Mr.Wizard Feb 23 '12 at 2:09
1  
@Mr.Wizard Yes, this question is a generalization of '1342'. –  Brett Champion Feb 23 '12 at 5:01

2 Answers 2

up vote 14 down vote accepted

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}} *)
share|improve this answer
    
+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
3  
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
1  
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

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]; // AbsoluteTiming
r2 = listMaxArgMrW[Tr, list]; // AbsoluteTiming
r1 === r2
{0.6770387, Null}

{0.2080119, Null}

True

As you can see listMaxArgMrW is over three times as efficient as listMaxArgRM, at least in version 7.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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