11

I have the following set:

list = {{32/39, 1/5, 0, 0, 0}, {5/33, 3/5, 1/3, 0, 3/4}};

I need to find the position of maximum value from each subset. I tried

Position[list, Max[list]]

and it gives the position {{1,1}}. But my result should be {{1,1}, {2,5}}/

kglr
  • 394,356
  • 18
  • 477
  • 896
Nirmal Baral
  • 111
  • 3
  • 4
    From the documentation for Ordering (=> Props and Relations), to find the position of the maximum element: Ordering[#1, -1] & /@ list -> {{1}, {5}}. See also here – user1066 Jan 27 '18 at 13:42

12 Answers12

11
Position[Unitize[# - Max @ #]& /@ list, 0]

{{1, 1}, {2, 5}}

Also:

MapIndexed[Join[#2, Ordering[#, -1]]&, list]
Join @@@ MapIndexed[Prepend, Position[#, Max @ #] & /@ list]

{{1, 1}, {2, 5}}

kglr
  • 394,356
  • 18
  • 477
  • 896
11

Here is an answer that makes extensive use of internal functions, but is significantly faster.

maxPositions[list_?MatrixQ] := With[
    {
    mask = UnitStep @ Subtract[
        list,
        Random`Private`MapThreadMax[Transpose@list]
    ]
    },
    Mod[Random`Private`PositionsOf[Flatten @ mask, 1], Dimensions[list][[2]], 1]
]

The function does not return the indices, only the maxima. Comparison:

data = RandomReal[10, {10^5, 5}];

r1 = maxPositions[data]; //RepeatedTiming
r2 = Position[Unitize[#-Max@#]&/@data,0]; //RepeatedTiming (* kglr *)

Thread[{Range[10^5], r1}] === r2

{0.00737, Null}

{0.088, Null}

True

The other answers are much slower.

Update

It seems that Random`Private`MapThreadMax was introduced between 10.3.1 and 11.1. For versions of Mathematica that don't have that function you can use:

maxPositions[list_?MatrixQ] := With[
    {mask = UnitStep[list + Random`Private`MapThreadMin[-Transpose@list]},
    Mod[Random`Private`PositionsOf[Flatten @ mask, 1], Dimensions[list][[2]], 1]
]
Carl Woll
  • 130,679
  • 6
  • 243
  • 355
9
MapIndexed[
 Join[#2, Position[#, Max[#]][[1]]] &
, list
]
Kuba
  • 136,707
  • 13
  • 279
  • 740
6
MapThread[Flatten@{#1, Position[#2, #3]} &,
 {Range@Length@list, list, Max /@ list}]
Chris Degnen
  • 30,927
  • 2
  • 54
  • 108
6
list = {{32/39, 1/5, 0, 0, 0}, {5/33, 3/5, 1/3, 0, 3/4}};

From the documentation for Max: "Max[{Subscript[x, 1], Subscript[x, 2],…}, {Subscript[y, 1],…},…] yields the largest element of any of the lists." Consequently,

Max[list]

(* 32/39 *)

From the documentation for Position: "Position returns a list of positions in a form suitable for use in Extract, ReplacePart, and MapAt. The form is different from the one used in Part."

pos = Position[list, Max[list]]

(* {{1, 1}} *)

Extract[list, pos]

(* {32/39} *)

If you want the Max of each of the sublists of list

Max /@ list

(* {32/39, 3/4} *)

pos2 = Position[#, Max[#]] & /@ list

(* {{{1}}, {{5}}} *)

Extract[list[[#]], pos2[[#]]] & /@ {1, 2}

(* {{32/39}, {3/4}} *)
Bob Hanlon
  • 157,611
  • 7
  • 77
  • 198
5
fun = Compile[{{x, _Real, 1}}, Position[x, Max[x]][[1, 1]] , 
Parallelization -> True, RuntimeAttributes -> {Listable}, RuntimeOptions -> "Speed",  CompilationTarget -> "C"]; 

{Range@Length@Flatten[list, {1}], fun[list]} // Transpose

Compile seems very fast :slightly slower than Carl's r1 on matrix with fewer than 10^4 points, faster on matrix with over 10^5 points)

Alucard
  • 2,639
  • 13
  • 22
4

This also works but slow for large list.

Join @@ (Position[list, #] & /@ Max /@ list)

Edit: Above code only works if elements are not repeated.

This one works for all cases and pretty fast.

Transpose@{Range@Length@list, Flatten[Position[#, Max[#]] & /@ list]}
OkkesDulgerci
  • 10,716
  • 1
  • 19
  • 38
4

Since Version 13.2 there is PositionLargest:

list = {{32/39, 1/5, 0, 0, 0}, {5/33, 3/5, 1/3, 0, 3/4}};

ps = PositionLargest /@ list

{{1}, {5}}

mi = MapIndexed[{#2[[1]], #1[[1]]} &] @ ps

{{1, 1}, {2, 5}}

Extract[mi] @ list

enter image description here

eldo
  • 67,911
  • 5
  • 60
  • 168
  • Thanks for pointing to PositionLargest (+1). I simply cannot remember this one. However, for X = RandomReal[{-1, 1}, {10000000}];, a call to Ordering[X, -1] takes just 0.0455106 seconds on my machine while PositionLargest[X] requires 0.385012 seconds. More than 8 times as long! (And more than 60 times as long as a similar C++ function would take...) =/ – Henrik Schumacher Jan 07 '24 at 14:08
  • 1
    Thanks, Henrik, I wasn't aware that PositionLargest is such a poor performer. Many of the newer functions (all of the Sequence-functions, DeleteElements etc.) are pretty slow. I hope, that WR will accelerate them in future releases. – eldo Jan 07 '24 at 17:05
4

Another method using MaximalBy:

Position[list, #][[1]] & @@@ (list // Map[x |-> MaximalBy[x, Position]])

({{1, 1}, {2, 5}})

Or using SortBy:

Position[list, #][[1]] & /@ Last /@ (SortBy[#, Position] & /@ list)

({{1, 1}, {2, 5}})

Or using GroupBy:

Values@((x |-> Position[list, x][[1]]) /@ AssociationMap[Reverse, GroupBy[list, x |-> Max[x]]])

({{1, 1}, {2, 5}})

Another possibility is to use GroupBy, Position and KeyMap as follows:

Keys@KeyMap[Position[list, #][[1]] &, GroupBy[list, Max]]

({{1, 1}, {2, 5}})

E. Chan-López
  • 23,117
  • 3
  • 21
  • 44
3

We could also use TakeLargest

list = {{32/39, 1/5, 0, 0, 0}, {5/33, 3/5, 1/3, 0, 3/4}};

max = Splice @ TakeLargest[# -> All, 1] & /@ list

enter image description here

Dataset @ max

enter image description here

Values @ max

{{32/39, 1}, {3/4, 5}}

To only get the positions:

Lookup[max, "Index"]

{1, 5}

Splice @ TakeLargest[# -> "Index", 1] & /@ list

{1, 5}

Positions of the two largest elements:

TakeLargest[# -> "Index", 2] & /@ list

{{1, 2}, {5, 2}}

eldo
  • 67,911
  • 5
  • 60
  • 168
2

Reinventing the bicycle here, but could be useful to someone.

list = {{32/39, 1/5, 0, 0, 0}, {5/33, 3/5, 1/3, 0, 3/4}};

Table[Flatten[{i, Position[aux = list[[i]], Max[aux]]}], {i, 1, 
Length[list]}]

{{1, 1}, {2, 5}}

Titus
  • 1,370
  • 9
  • 18
2

Using Threshold:

list = {{32/39, 1/5, 0, 0, 0}, {5/33, 3/5, 1/3, 0, 3/4}};

pos = list // Map[Threshold[#, {"LargestValues", 1}] &] // Position[#, Except[0], {2}, Heads -> False] & // GatherBy[#, First] &

{{{1, 1}}, {{2, 5}}}

Extract[list, #] & /@ pos

{{32/39}, {3/4}}

Syed
  • 52,495
  • 4
  • 30
  • 85