Update: Added to test table below new 3 answers.
I came up with an improvement to my earlier method. Instead of running the Ordering on the original list, why not run it on a much smaller list? of only 3 items !
This new list is first generated from the original list like this:
{Abs[#], Max[#], Min[#]} & /@ list
Now with only 3 elements in each list, it is much faster to do the same thing as before.
The idea is to check if first element same as Abs
of 3rd element. If not, then use the middle element, else use the third. So it is only an If
added to each element. Min/Max/Abs so the heavy work:
If[#[[1]] == Abs@#[[3]],#[[3]], #[[2]]] & /@({Max@Abs[#], Max[#], Min[#]}& /@ list)
UPDATE TIMING
All run on V 9.01, windows 7, 64 bit. Intel core i7. Using this list
list = RandomInteger[{-30, 30}, {50000, 20}];
Using this list
list = RandomReal[{-9, 9}, {50000, 20}];
Appendix
Test code:
SetAttributes[timeAvg, HoldFirst]
timeAvg[func_] :=
Do[If[# > 0.3, Return[#/5^i]] & @@ Timing@Do[func, {5^i}], {i, 0, 15}]
MrWizardPick[a_] := Pick[a, #, Max@#] &@Abs@a ;
(*list=RandomInteger[{-30,30},{50000,20}];*)
MaxBy[list_, fun_] := list[[First@Ordering[fun /@ list, -1]]];
list = RandomInteger[{-30, 30}, {50000, 20}];
gpap = Block[{M, m}, M = Max@#;
m = Min@#;
If[M > -m, M, m]] &;
Grid[{
{"Gpap", gpap /@ list // timeAvg},
{"Simon", If[+## > 0, ##] & @@ {Max[#], Min[#]} & /@ list // timeAvg},
{"Nasser", If[#[[1]] == Abs@#[[3]], #[[3]], #[[2]]] & /@ ({Max@Abs[#], Max[#],
Min[#]} & /@ list) // timeAvg},
{"Blackbird",Table[If[
Min[list[[i]]] < 0 && Abs[Min[list[[i]]]] > Max[list[[i]]],
Min[list[[i]]], Max[list[[i]]]], {i, Length[list]}] // timeAvg},
{"Tom",Pick[Flatten@#, Flatten[Ordering@Ordering@Abs[#] & /@ #], 3] &@ list // timeAvg},
{"MrWizard", #~Extract~Ordering[Abs@#, -1] & /@ list // timeAvg},
{"Pinguin",Max /@ Pick[list, UnitStep[# - Max[#]] & /@ (Abs@list), 1] // timeAvg},
{"Kuba", (SortBy[#, Abs] & /@ list)[[;; , -1]] // timeAvg},
{"Rojo", Pick[list,
With[{absList = Abs@list},
With[{max = Max /@ absList}, # - max & /@ Transpose@absList] //
Unitize // Transpose], 0] // Flatten // timeAvg},
{"MrWizardPick", MrWizardPick /@ list // timeAvg},
{"Szabolcs", MaxBy[#, Abs] & /@ list // timeAvg}
}, Frame -> All, Alignment -> Left, Spacings -> {.5, 1}]
{1,2,2}
? You'd pick 2 just once or twice? $\endgroup${1,-2,2}
:) $\endgroup${1,-2,2}
should return2
. $\endgroup$-2
is single result which fits too:) MyMapIndexed
method will give you the first of "equal" numbers. Switching to<=
will result in the last one of them but there is a case of{-2,2,-2}
. Then You will always get-2
unless you restate the question to be more precise that you want positive value from the "equal" set. $\endgroup$