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.

Starting with

{{0, 0, 0}, {1, 1, 2}, {2, 3, 3}, {3, 4, 5}}

I would like to get

{{0, 2, 3, 5}, {1, 3, 2, 3}}

where the first list returned is the highest value reached in each of the first lists, and the second output is the position of the highest values that were reached in each list.

I have been trying different combinations of Max and Position, but have been unsuccessful.

share|improve this question
1  
Someone is robo-down-voting. :-p –  Mr.Wizard Jan 11 at 19:03
    
I must admit, I do find the politics on this site rather amusing ;) –  martin Jan 11 at 19:03
    
@Mr.Wizard There's only one vote on the entire thread, so not really "robo"... just someone that's unhappy (there probably were worse questions that they should've spent that downvote on) :) –  rm -rf Jan 11 at 19:09
    
@rm-rf You missed it, but someone came by and downvoted the question and every answer, including yours. Then apparently the removed they votes on the answers, but left the -1 on the question. –  Mr.Wizard Jan 11 at 19:12
    
@Mr.Wizard Ah, I didn't see that. That's indeed strange. –  rm -rf Jan 11 at 19:14

4 Answers 4

up vote 5 down vote accepted
dat = {{0, 0, 0}, {1, 1, 2}, {2, 3, 3}, {3, 4, 5}};

f[a_] := {#, Position[a, #, 1, 1][[1, 1]]} & @ Max[a]

Transpose[f /@ dat]
{{0, 2, 3, 5}, {1, 3, 2, 3}}

Since your lists are "very long" here is a faster method using my favorite trick: SparseArray Properties.

f2[a_] := {#, First @ SparseArray[UnitStep[a - #]]["AdjacencyLists"]} & @ Max @ a

Transpose[f2 /@ dat]
{{0, 2, 3, 5}, {1, 3, 2, 3}}

Performance comparison on a big array:

dat = RandomInteger[1*^9, {1000, 100000}];

Transpose[f /@ dat]  // Timing // First
Transpose[f2 /@ dat] // Timing // First
3.9

0.515
share|improve this answer
    
@ Mr Wizard, thanks for the time you have given to this - I will test once Mathematica has evaluated what I have given it! –  martin Jan 11 at 19:29
1  
@Mr.Wizard you do have a fast computer: mathematica.stackexchange.com/questions/28209/… –  s0rce Jan 11 at 20:29
    
@s0rce I use version 7 which seems to be faster than later versions in a number of cases of basic programming. But yes, I have found clock speed to correlate well with Mathematica performance and I run an unlocked i5-2500K CPU at 4.6 GHz. –  Mr.Wizard Jan 11 at 20:34
    
@Mr.Wizard f2 is surprisingly much faster than the typical C solution, when compiled (on my computer). –  VF1 Jan 11 at 20:58
    
@VF1 That's an interesting finding. I know that the code behind SparseArray generation is highly optimized which is why it often outperforms more obvious and direct solutions, at least in version 7. Have you tried compiling Position to C? I recall someone reporting that as being very fast. –  Mr.Wizard Jan 13 at 9:00

Using Ordering is another option, and more efficient if you have long lists/sublists:

dat = {{0, 1, 0}, {3, 1, 2}, {2, 3, 4}, {5, 3, 4}}; (* different example with a unique max *)
With[{l = #}, Composition[{l[[#]], #} &, Last, Ordering]@#] & /@ dat // Transpose
(* {{1, 3, 4, 5}, {2, 1, 3, 1}} *)

Note that if you have more than one element that is the maximum, then Ordering will only give you the last index.

share|improve this answer
1  
But that's not the example that martin gave; I assume he specifically chose an example with repeated maximums, and wanted only the first position. –  Mr.Wizard Jan 11 at 18:53
    
I have very long lists! Many thanks :) –  martin Jan 11 at 18:53
    
@Mr.Wizard Well, we don't know and that's the problem with underspecified questions :) –  rm -rf Jan 11 at 18:53
    
@ Mr Wizard, that is true - will try all now –  martin Jan 11 at 18:54
    
@martin Which result do you actually want? –  Mr.Wizard Jan 11 at 18:54

Another option:

list = {{0, 0, 0}, {1, 1, 2}, {2, 3, 3}, {3, 4, 5}}

maxWithPosition[list_] := 
 With[{max = Max /@ list}, {max, 
   MapThread[Position, {list, max}][[All, 1, 1]]}]

maxWithPosition[list]
{{0, 2, 3, 5}, {1, 3, 2, 3}}
share|improve this answer

If speed is an issue, and you're using numeric values, I would go for Compile. This will only work for data types that are compilable, such as _Integer or _Real, but those seem to be the only ones OP is interested in.

Here's the fastest I could come up with:

Module[{cfn1},
 cfn1 = Compile[{{list, _Integer, 1}},
        Module[{temp, max = First@list, maxp = 1},
     Do[temp = list[[i]]; 
      If[temp > max, max = temp; maxp = i], {i, Length@list}];
     {max, maxp}
     ], CompilationTarget -> "C"];
 singlePassC[arg : {__Integer}] := cfn1[arg];
 singlePassC[{}] = {};
 ]

I noticed some interesting timing trends, though, compared to Mr.Wizard's function. Consider the more Mathematica-like Compiled implementation for finding the maximum position:

Module[{cfn1},
 cfn1 = Compile[{{list, _Integer, 1}},
    With[{max = Max@list}, {{{max}}, Position[list, max]}],
    CompilationTarget -> "C"];
 twoPassC[arg : {__Integer}] := cfn1[arg][[All, 1, 1]];
 twoPassC[{}] = {};
 ]
     (* Mr. Wizard's non-compiled implementation *)
sparseArrayME[
  a_] := {#, First@SparseArray[UnitStep[a - #]]["AdjacencyLists"]} &@ Max@a

All of these work:

sparseArrayME@{3, 5, 4} ===
 singlePassC@{3, 5, 4} ===
 twoPassC@{3, 5, 4} ===
 {5, 2}
 (* True *)

But notice these peculiar timings:

dat = RandomInteger[1*^9, {100000000}];
datm = RandomInteger[1*^9, {1000, 100000}];
test[f_] := f@dat // Timing // First
testm[f_] := f /@ datm // Transpose // Timing // First
funcs = {sparseArrayME, singlePassC, twoPassC};
{{"Data Type", "Sparse Array", "Single Pass C", "Two Pass C"},
  Prepend[test /@ funcs, "Single Array"],
  Prepend[testm /@ funcs, "Matrix"]} // TableForm

results

So Mr.Wizard's uncompiled SparseArray properties is faster than a compiled Position when applied to many smaller-sized sublists. I doubt this is because of the deeper nesting I am forced to make in twoPassC's cfn1 which I then extract from in the actual function - that shouldn't be what takes so long.

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.