# Minimum and maximum values under conditions

Let's create some sample data

n = 10;
data = Table[{RandomReal[], RandomReal[], RandomReal[], RandomReal[],
RandomInteger[{-1, 2}], RandomInteger[{0, 15000}]}, {i, 1, n}]


Now, I want to find the minimum and the maximum value of the last column (#6) only when the fifth one has an integer value 1 or 2, thus excluding the -1 and 0.

Any suggestions?

Not pretty, but work

#@Select[data,MemberQ[#,Alternatives@@{1,2}]&][[All,6]]&/@{Max,Min}

• It works like a charm. Thank you very much! – Vaggelis_Z Jul 29 '14 at 9:11
• @Vaggelis_Z I suggest you use a different method. This code performs the same selection redundantly, once for Max and once for Min. – Mr.Wizard Jul 30 '14 at 12:56
• @Mr.Wizard I don't quite understand your point. Could you elaborate (explain) it a little bit more? – Vaggelis_Z Jul 30 '14 at 14:30
• @Vaggelis_Z My point is that this is not efficiently written. Select is part of the function that is mapped to {Max,Min} therefor the selection is run twice. Worse, the selection function is not focused on the fifth column: it is checking for a 1 or 2 anywhere in the sublist. While for the given example this does not change the result it is hardly correct. – Mr.Wizard Jul 30 '14 at 14:50
• @Vaggelis_Z If it is the use of Alternatives that you like consider: {Min@#, Max@#} & @ Pick[#6, #5, 1 | 2] & @@ (data\[Transpose]) – Mr.Wizard Jul 30 '14 at 14:55

Though it isn't the focus of your question there is a much faster way to generate your example data:

Join[RandomReal[1, {n, 4}], Transpose[RandomInteger[#, n] & /@ {{-1, 2}, 15000}], 2]


For the problem itself I also chose Pick but I used Transpose and Positive instead:

{Min@#, Max@#} & @ Pick[#6, Positive @ #5] & @@ (data\[Transpose])


This proves to be about twice as fast as sebhofer's code:

n = 1*^6;

data = Join[RandomReal[1, {n, 4}], Transpose[RandomInteger[#, n] & /@ {{-1, 2}, 15000}], 2]

{Min@#, Max@#} & @ Pick[#6, Positive @ #5] & @@ (data\[Transpose])         // Timing // First

Through[{Max, Min}@Pick[data[[;; , 6]], HeavisideTheta@data[[;; , 5]], 1]] // Timing // First

0.162241

0.343202


(Timings performed in version 10.0.)

• The Pick method seems the most intuitive. I was about to post my answer but I see that @Mr.Wizard already came up with it (of course). – seismatica Jul 30 '14 at 0:43
• Well that was just a matter of time, wasn't it... :) – sebhofer Jul 30 '14 at 8:23
• I think my new version is even faster though! – sebhofer Jul 30 '14 at 13:11
• @sebhofer I can confirm that it is faster, and I'm not too surprised. Nevertheless like using Transpose as it lets me address columns with simply #5 or #6 which IMO make things much nicer to read. By the way you already had my vote. :-) – Mr.Wizard Jul 30 '14 at 14:15
• @sebhofer It seems the transpose is costly because the data is not packed. Thread is actually faster in this case, but it doesn't match Part. With packed data such as data = RandomReal[{-2, 2}, {1*^6, 6}]; my code is still slightly faster than yours. :^) – Mr.Wizard Jul 30 '14 at 14:19

Slightly faster alternative (about factor of 10 speedup compared to accepted solution):

Through[{Max, Min}@Pick[data[[;; , 6]], HeavisideTheta@data[[;; , 5]], 1]]


Edit

And even a bit better

Through[{Max, Min}@Pick[data[[;; , 6]], Positive@data[[;; , 5]]]]


which I think is even a bit faster than Mr.Wizard's current method.

MaximalBy, build-in function in v10.0.0.

f[list_] :=
With[{x = list[[5]]}, If[x == 1 || x == 2, list[[6]], -1]];
MaximalBy[data, f]

• Unfortunately, I have v9.0. Thanks BTW. – Vaggelis_Z Jul 29 '14 at 9:07