# 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...

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[] &]
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 Mar 17, 2012 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? Mar 18, 2012 at 2:28
• Comparison based sorting is at least $\mathcal O(n\log n)$. Mar 18, 2012 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 Mar 17, 2012 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. Mar 17, 2012 at 21:38
• Congrats on being the first 10k user! :)
– rm -rf
Mar 17, 2012 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 Mar 17, 2012 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? Mar 19, 2012 at 20:18
• @Szabolcs I have to agree that doesn't make sense. Also, convoluted may not have been the best choice of words. Mar 19, 2012 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. Jun 23, 2015 at 10:59
• @kirma Do you mind if I add that to my answer? Jun 23, 2015 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= {{0, 8}, {1, 9}, {2, 9}}
Out= {{0, 8}, {1, 9}, {2, 9}}


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

{90, 76, 75}


while this three minimal x- elements :

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

{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 Mar 17, 2012 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]. Mar 17, 2012 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? Aug 28, 2014 at 3:40
• @Crisp Consider using SortBy or new in version 10 MaximalBy, e.g. MaximalBy[ list, Last]. Aug 28, 2014 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, 2012 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, 2012 at 0:10
trr = RandomReal[{1, 7}, {5, 2}]

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

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

• I think your answer is slightly different from what OP asked for. May 15, 2013 at 11:49