Thanks to all for your hints.
Maybe I was not really clear with my question. I want to get the maximum of a list and ALL its positions. Sander, I did not understand, how I could avoid Position. I made some test meanwhile:
What I really want to have is a WL-function that delivers the largest entry of a list and all their positions in that list. Something like {max,poss}=FindLargest[list], where poss is the list of positions with value max within list. But this does not seem to exist in WL. I made some tests with different solutions using TakeLargest, Max and Ordering together with Position. They are all similar fast, Max and Ordering being slightly faster than TakeLargest.
Programming findLargest manually ist easy, but very slow. See the last solution below.
Our example-list:
listLength = 10000000;
SeedRandom[471117];
list = RandomInteger[{1, Round[listLength/10]}, listLength];
Print["A list with ", listLength, " entries ranging from 1 to ",
Round[listLength/10], "\n", Short[list]];
A list with 10000000 entries ranging from 1 to 1000000
{784246,826384,700864,590699,641241,597870,<<9999988>>,115297,533997,724089,645211,308921,721824}
Show results t,max,poss from function findFunc on list list:
show[t_, max_, poss_List, findFunc_Symbol, findFuncTxt_String, list_List] :=
Print[Column[{
Style[Row[{findFunc, " (", findFuncTxt, "): ", Round[absTime, 0.001],
" sek. Max=", max, " at ", Length[poss], "/", Length[list], " poss:"}],
Blue],
Short[poss]
}]
]
Use TakeLargest and Position. Pretty fast even though list is scanned twice:
findLargest1[list_List] := Module[{max, poss},
(* Find largest element in list *)
{max} = TakeLargest[list, 1];
(* Find all positions of largest element in list *)
poss = Flatten[Position[list, max]];
(* Return *)
{max, poss}
]
absTime = AbsoluteTime[];
{max, poss} = findLargest1[list];
absTime = AbsoluteTime[] - absTime;
show[absTime, max, poss, findLargest1, "TakeLargest & Position", list];
findLargest1 (TakeLargest & Position): 0.923 sek. Max=1000000 at 10/10000000 poss:
{39794,299330,1695095,3366172,3779495,4947531,5083363,5596437,7052596,8823588}
Use Max and Position. Not very different from TakeLargest. Pretty fast even though list is scanned twice:
findLargest2[list_List] := Module[{max, poss},
(* Find largest element in list *)
max = Max[list];
(* Find all positions of largest element in list *)
poss = Flatten[Position[list, max]];
(* Return *)
{max, poss}
]
absTime = AbsoluteTime[];
{max, poss} = findLargest2[list];
absTime = AbsoluteTime[] - absTime;
show[absTime, max, poss, findLargest2, "Max & Position", list];
findLargest2 (Max & Position): 0.863 sek. Max=1000000 at 10/10000000 poss:
{39794,299330,1695095,3366172,3779495,4947531,5083363,5596437,7052596,8823588}
Use Ordering and Position. Sounds very expensive since list seems to be fully sorted and scanned twice. But this is not true. It is not very different from the solutions with TakeLargest or Max.
Unfortunately Ordering[list,-1] does not deliver all positions of the maximum, but only the first one:
findLargest3[list_List] := Module[{max, poss, pos},
(* Find largest element in list *)
{pos} = Ordering[list, -1];
max = list[[pos]];
(* Find all positions of largest element in list *)
poss = Flatten[Position[list, max]];
(* Return *)
{max, poss}
]
absTime = AbsoluteTime[];
{max, poss} = findLargest3[list];
absTime = AbsoluteTime[] - absTime;
show[absTime, max, poss, findLargest3, "Ordering & Position", list];
findLargest3 (Ordering & Position): 0.846 sek. Max=1000000 at 10/10000000 poss:
{39794,299330,1695095,3366172,3779495,4947531,5083363,5596437,7052596,8823588}
What I really want to have is a WL-function that delivers the largest entry of a list and all their positions in that list. Something like the following manually programmed. But this is horribly expensive.:
findLargest[list_List] := Module[{max, poss, entry},
(* Initialize *)
max = -Infinity; (* the current maximum of all entries *)
(* Run through all elements in list and collect the largest together with \
their positions *)
For[i = 1, i <= Length[list], i++,
entry = list[[i]]; (* the current element of the list *)
Switch[Sign[entry - max],
(* A new larger entry than max.
Start a new collection on poss and begin it with i *)
+1, max = entry; poss = {i},
(* entry is less than current max. Do nothing *)
-1, ,
(* entry is equal to max. Collect it into poss *)
0, AppendTo[poss, i]
]
];
(* Return *)
{max, poss}
]
absTime = AbsoluteTime[];
{max, poss} = findLargest[list];
absTime = AbsoluteTime[] - absTime;
show[absTime, max, poss, findLargest, "My programmed solution", list];
findLargest (My programmed solution): 27.694 sek. Max=1000000 at 10/10000000 poss:
{39794,299330,1695095,3366172,3779495,4947531,5083363,5596437,7052596,8823588}