How to find all the positions of max value of a list efficiently?
A fast uncompiled alternative without pattern matching is to use the NonzeroPositions
property of SparseArray
, as long as you're dealing with numerical data.
list = RandomInteger[{1, 100}, 10^7];
SparseArray[Unitize[list - Max[list]] - 1]["NonzeroPositions"]; // RepeatedTiming
(* 0.0855 *)
Position[list, Max[list]] // RepeatedTiming
(* 0.509 *)
compPos[list, Max[list]] // RepeatedTiming (* Marius' solution *)
(* 0.0366 *)
SparseArray[Unitize[list - Max[list]], Automatic, 1][
"NonzeroPositions"]; // RepeatedTiming (* MichaelE2's solutions *)
(* 0.0663 *)
For a 1D list you can also use
Pick[Range@Length@list, list, Max@list]
For a one-dimensional list:
compPos =
Compile[{{list, _Integer, 1}, {max, _Integer}},
Block[{copy = list, i = 1},
Do[
If[
list[[j]] == max, copy[[i++]] = j],
{j, Length[list]}];
copy[[1 ;; i - 1]]
],
CompilationTarget -> "C"
];
Though I think Position
is a good non-compiled alternative in this case, since the "pattern" you use is a number. There won't be any useless matches to this pattern.
Performance Test
list = RandomInteger[{1, 100}, 10^7];
Position[list, Max[list]] // AbsoluteTiming // First
0.8220470
compPos[list, Max[list]] // AbsoluteTiming // First
0.0830048
Obviously, 10 times speed-up