# Mathematica: finding min/max in list

I have a list of coordinates like this one:

{{x1,y1},{x2,y2},{x3,y3},...,{xn,yn}}


I need to get the minimum and the maximum of all x-values and the minimum and maximum of all y-values. Is this possible? If I use the in-built Min function for example gives me just the minimum of all x and y values...

-

## 7 Answers

Well, you could extract the y values and then calculate their minimum.

rand = RandomInteger[{0, 9}, {10, 3}]

{{6, 5, 2}, {3, 8, 3}, {0, 4, 0}, {3, 7, 5}, {4, 2, 7}, {6, 4, 5}, {3, 3, 3}, {7, 9, 7}, {4, 5, 5}, {4, 2, 5}}

Min[ rand[[All, 2]] ] (* 1 = x, 2 = y, 3 = z *)
Max[ rand[[All, 2]] ]

2
9


Another approach is of course sorting the list by user-defined rules and then picking the first/last element. For example, the following sorts the list according to ascending y values, and then extracts the min/max from that.

sorted = Sort[rand, #1[[2]] < #2[[2]] &]
sorted[[1, 2]] (* Minimal y *)
sorted[[-1, 2]] (* Maximal y *)

2
9


Note that this actually sorts the whole list, which is far less effective computationally. Normally, min/max functions don't sort, they just search.

-
Hi David, thanks a lot for your answer and your help. Harald – Harald Mar 17 '12 at 21:35
Isn't it so that sorting can be O(log(n)) whereas scanning the list for the max or min is at best O(n)? Could it be that soting and picking might be the fastest way? – Reb.Cabin Mar 18 '12 at 2:28
Comparison based sorting is at least $\mathcal O(n\log n)$. – David Mar 18 '12 at 4:09

You can use Min[ data[[All, 1]] ] to get the minimum of the x values. Or, to get a bit fancier,

Through /@ {Min, Max} /@ Transpose[data]


will give you the minimum and the maximum of the x and the y values in one go.

-
Hi Szabolcs, thanks a lot for your help and your answer to my problem. Harald – Harald Mar 17 '12 at 21:36
@user1276227 Hei Harald and welcome to StackExchange! :-) I hope you'll like it here. I see your account is unregistered. I recommend you register and enter your name in your profile. Also, please do not cross post the same question between multiple SE sites (cross posting to mailing lists or non-SE sites is okay). For Mathematica-related questions this site is best---you'll get answers quickly here. – Szabolcs Mar 17 '12 at 21:38
Congrats on being the first 10k user! :) – R. M. Mar 17 '12 at 22:03

The more direct application of Map, that is:

{Min@#, Max@#} & /@ Transpose[dat]


is an order of magnitude faster than Szabolcs's pretty but convoluted method:

SetAttributes[timeAvg, HoldFirst]

timeAvg[func_] :=
Do[If[# > 0.3, Return[#/5^i]] & @@ Timing@Do[func, {5^i}], {i, 0, 15}]

dat = RandomInteger[1*^7, {500000, 2}];

Through /@ {Min, Max} /@ Transpose[dat]; // timeAvg

{Min@#, Max@#} & /@ Transpose[dat]; // timeAvg

0.0362

0.003368


### Version 10.1 update

Mathematica 10.1 introduced MinMax and (as kirma informed me) CoordinateBounds. MinMax is no faster than {Min@#, Max@#} & in this case; CoordinateBounds happily is several times faster!

dat = RandomInteger[1*^7, {500000, 2}];

{Min@#, Max@#} & /@ Transpose[dat] // RepeatedTiming
MinMax /@ Transpose[dat]           // RepeatedTiming
CoordinateBounds[dat]              // RepeatedTiming

{0.0055,  {{35, 9999992}, {9, 9999948}}}

{0.00548, {{35, 9999992}, {9, 9999948}}}

{0.0011,  {{35, 9999992}, {9, 9999948}}}


(Timings performed in 10.1 rather than 7.0.1 as with the first group of timings. Also RepeatedTiming used instead of timeAvg.)

-
Hi Mr. Wizard, thanks a lot for your comment and your help, Harald – Harald Mar 17 '12 at 22:48
+1 (already when you answered) but I don't find my method convoluted. I think it's natural once you get used to Through. Of course now that you pointed out that this version is so much faster, I'd use this one. The strange thing is that Through forces the array to be unpacked. I don't understand why. I don't see why this is necessary ... could even call it a bug or an oversight? – Szabolcs Mar 19 '12 at 20:18
@Szabolcs I have to agree that doesn't make sense. Also, convoluted may not have been the best choice of words. – Mr.Wizard Mar 19 '12 at 22:04
@Mr.Wizard v10.1 also introduces CoordinateBounds, which does precisely what OP was asking, and is documented to be equivalent to your MinMax variant. – kirma Jun 23 '15 at 10:59
@kirma Do you mind if I add that to my answer? – Mr.Wizard Jun 23 '15 at 11:04

Szabolcs's answer is how I would've done it, but just for fun, you can also use an undocumented function RandomPrivateMapThreadMin to achieve the same result for the minimum values. However, there isn't an equivalent RandomPrivateMapThreadMax, so we just negate the arguments and then the output. The following:

{RandomPrivateMapThreadMin[#], -RandomPrivateMapThreadMin[-#]} &@ list//Transpose


will give you the same result as Szabolcs's answer. Example:

list = RandomInteger[{0, 9}, {10, 3}];
{RandomPrivateMapThreadMin[#], -RandomPrivateMapThreadMin[-#]} &@ list//Transpose
Through /@ {Min, Max} /@ Transpose[list]

Out[1]= {{0, 8}, {1, 9}, {2, 9}}
Out[2]= {{0, 8}, {1, 9}, {2, 9}}

-
Hi, thanks a lot for your answer, which helps me to learn more and more about Mathematica. Harald – Harald Mar 17 '12 at 22:45

You can also use new functions in version 8 like RankedMax and RankedMin.

list = RandomInteger[{0, 100}, {10, 2}]

{{44, 9}, {74, 0}, {56, 40}, {45, 56}, {0, 76}, {88, 90}, {14, 19},
{77, 64}, {4, 75}, {81, 56}}


This yields three maximal y- elements :

RankedMax[list[[All, 2]], #] & /@ Range[3]

{90, 76, 75}


while this three minimal x- elements :

RankedMin[list[[All, 1]], #] & /@ Range[3]

{0, 4, 14}


RankedMax[list[[All, 2]], n] gives n-th maximal y-element.

-
Hi Artes, thanks a lot for your hints. Never noticed these new functions up to now... Harald – Harald Mar 17 '12 at 22:47
@Harald You can successfully use built-in functions since in general they are optimized. Note e.g. RankedMax[list[[All, 2]], Length@list] is equivalent to Min[[All,2]], though it would be better to use RankedMin[list[[All, 2]], 1]. – Artes Mar 17 '12 at 23:00
@Artes what would you do to your code to get both parts instead of one cordinate? for example to get the nth maximal value of x or y and it outputs the x and y cordinate as well? – Crisp Aug 28 '14 at 3:40
@Crisp Consider using SortBy or new in version 10 MaximalBy, e.g. MaximalBy[ list, Last]. – Artes Aug 28 '14 at 10:38

The following, suprisingly, is almost as fast as Mr.Wizard's approach, and it provides added flexibility to get ranks different from Min and Max or ranges of ranks as well as the ability to specify any ordering function:

  {#[[Ordering[#, 1]]], #[[Ordering[#, -1]]]} & /@ Transpose[dat]


Alternatively, one can re-organize the left part:

  #[[Flatten@{Ordering[#, 1], Ordering[#, -1]}]] & /@ Transpose[dat]


Additional flexibility comes from the ability to use the second and third arguments of Ordering.

To get the second smallest and third largest elements, use as

 {#[[Ordering[#, 2]]], #[[Ordering[#, -3]]]} & /@ Transpose[dat]


To get the bottom 4 and top 5 elements:

 {#[[Ordering[#, {1,4}]]], #[[Ordering[#, {-5,-1}]]]} & /@ Transpose[dat]


To get odd-ranked and even-ranked elements:

 {#[[Ordering[#, {1,-1,2}]]], #[[Ordering[#, {2,-1,2}]]]} & /@ Transpose[dat]


To get the smallest and largest elements when elements are ordered by Abs:

 {#[[Ordering[#, 1, Abs[#1] < Abs[#2] &]]],
#[[Ordering[#, -1,Abs[#1] < Abs[#2] &]]]} & /@ Transpose[dat]


etc...

-
+1. I did think about ordering, but used to think it was going to be terribly slow. – FJRA Mar 18 '12 at 19:02
@FJRA, actually Ordering is usually faster than alternatives like Sort, SortBy; but I too was surprised to find that it is as fast as it is when the task is just plain vanilla Min,Max. – kglr Mar 19 '12 at 0:10
trr = RandomReal[{1, 7}, {5, 2}]

Select[trr, #[[2]] == Max[trr[[All, 2]]] &](*Maximal y, in the pairs {xi,yi} *)

Select[trr, #[[1]] == Min[trr[[All, 1]]] &](*Minimal x, in the pairs {xi,yi} *)

-
I think your answer is slightly different from what OP asked for. – Silvia May 15 '13 at 11:49