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.

This question already has an answer here:

I have a nested list of {x,y,z} and I want to find out the values of x and y where z is minimum. I can write a nested For loop and do it

mya = {{0, 1, 10}, {1, 1, 20}, {0, 2, 5}, {1, 2, 15}}

For[i = 1, i <= Length[mya[[All, 3]]], i++, 
If[mya[[All, 3]][[i]] == Min[mya[[All, 3]]], Print[mya[[i]]]]]

I get the desired output:

{0, 2, 5}

I know this problem is simple, but if someone can tell me a more elegant way to do it, it will be helpful as I wanna do it for a very large list.

share|improve this question

marked as duplicate by Mr.Wizard Jul 26 at 23:37

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

    
Cases[mya, x_ /; x[[3]] == Min[mya[[All, 3]]]] is another option –  Nasser Feb 14 at 12:42
1  
@Nasser : I posted a similar answer. Concerning your solution, I thought the part Min[mya[[All, 3]]] is evaluated Length@mya times. It may be better to let it only evaluate once as I did. –  Yi Wang Feb 14 at 12:49
    
I have marked this question a duplicate because I believe that any method that works for maximum can be directly adapted for minimum, making the solutions effectively identical. (This question will remain as pointer.) If anyone disagrees with this action please leave a comment. –  Mr.Wizard Jul 26 at 23:39

5 Answers 5

up vote 6 down vote accepted

I think @halirutan's answer is quite nice and clean. Nevertheless just give an alternative one:

findLastMin[mat_] := Cases[mat, {__, Min@mat[[All, -1]]}]

findLastMin[mya]

{{0, 2, 5}}

There is additional {...} outside the desired output by the OP, because if there are multiple equal minimal values, it returns them all.

share|improve this answer

How about using SortBy to sort your list by the last element and then take the first entry?

First[SortBy[mya, Last]]
(* {0, 2, 5} *)

A simple iterative approach to go through your list exactly once and remember the minimum element can be written as

Block[{min = First[mya]},
 Do[If[Last[min] > Last[elm], min = elm], {elm, Rest[mya]}];
 min
]

Although my tests showed that this is a bit slower (about 2 seconds for 10^7 elements) as the first approach.

An faster approach then the two above is to first extract the minimum of all z-values and then go through the list until you hit the first match

Block[{min = Min[Last[Transpose[mya]]]},
 Do[If[Last[elm] === min, Return[elm]], {elm,mya}]
]
share|improve this answer
    
Thanks. I was trying to do this with a list of 60,000 length and sort seems to work much faster than For loop!! –  MathBiolGuy Feb 14 at 12:31
    
Man, you are on a roll today :). This is my third upvote to your today's answers. Looks like you have some plot against Mr.Wizard :). –  Leonid Shifrin Feb 14 at 12:41
    
@LeonidShifrin For the last weeks I barely had time to look at the site and today I just took some minutes and found some nice questions. But thanks. –  halirutan Feb 14 at 12:46

An alternate solution using Fold:

Fold[If[Last[#2] < Last[#1], #2, #1] &, {0, 0, Infinity}, mya]

If the list is known to be non-empty, the following solution is faster:

Fold[If[Last[#2] < Last[#1], #2, #1] &, First[mya], Rest[mya]]
share|improve this answer

Thanks everyone for the reply. Didn't expect such an overwhelming response. I did a quick check on the speed of each of the solutions by making a random list of 2x10^7 elements and compared the timing (given in bold) using the 4 solutions given by Yi Wang, halirutan and sakra:

a = RandomInteger[1000, {2*10^7, 3}];

Method 1:

findLastMin[mat_] := Cases[mat, {__, Min@Last@Transpose@mat}]
findLastMin[a] // Timing

{8.020000, {{710, 337, 0}, {347, 509, 0}, <<19744>>, {609, 151, 0}, {553, 806, 0}}}

Method 2:

First[SortBy[a, Last]] // Timing

{18.216000, {0, 28, 0}}

Method 3:

Block[{min = Min[Last[Transpose[a]]]}, 
Do[If[Last[elm] === min, Return[elm]], {elm, a}]] // Timing

{2.536000, {710, 337, 0}}

Method 4:

Fold[If[Last[#2] < Last[#1], #2, #1] &, {0, 0, Infinity}, a] // Timing

{29.132000, {710, 337, 0}}

Method 1 gives all solutions and is fairly quick. Once again thanks for all the solutions.

share|improve this answer

Not very efficient, I suspect, but two other (related) possibilities:

#[[Position[Ordering@Ordering@#[[All, 3]], 1, 1, 1][[1, 1]]]] &@mya

=>

{0, 2, 5}

Pick[#, Ordering@Ordering@#[[All, 3]], 1] &@mya

=>

{{0, 2, 5}}

share|improve this answer

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