7
$\begingroup$

Suppose I have a matrix m={{1,2,3},{3,-2,1/3}};

I want to find the positions of, for example, 2 largest elements in each row that is above 1/2.

So, in m, 2 and 3 are the ones in the first row and 3 is the one in the second row. Thus, the output should be their positions:

{{1,2},{1,3},{2,1}}

I tried to use Position[m, _?(# > 1/2 &)] but this will only find the position of elements that is above 1/2..

How can I do this?

$\endgroup$

3 Answers 3

8
$\begingroup$

Update: Shorter variations:

ClearAll[taken, takem, takek]
taken[condition_, n_] := Apply[Join] @*
  MapIndexed[Thread[{#2[[1]], 
    Select[Function[x, condition @ #[[x]]]] @ TakeLargest[# -> "Index", n]}] &]

takem[condition_, m_] := Apply[Join] @*
  MapIndexed[Thread[{#2[[1]], 
    Select[Function[x, condition @ #[[x]]]] @ Ordering[#, -m]}] &]

takek[condition_, k_] := MapIndexed[Sequence @@ Thread[{#2[[1]], #}] &] @*
  Map[Cases[{a_ /; condition[a], b_} :> b] @
      Nearest[# -> {"Element", "Index"}, Max @ #, k] &]

Examples:

taken[GreaterEqualThan[1/2], 2] @ m
{{1, 3}, {1, 2}, {2, 1}}
takem[GreaterEqualThan[1/2], 2] @ m
{{1, 3}, {1, 2}, {2, 1}}
takek[GreaterEqualThan[1/2], 2] @ m
{{1, 3}, {1, 2}, {2, 1}}

Original answer:

ClearAll[take]
take[condition_, n_] := Apply[Join] @* 
  MapIndexed[Thread[{#2[[1]], #}] &] @*
  Map[Map[#Index &] @
   Select[condition @ #Element &] @
   TakeLargest[# -> All, n]&]

Examples:

take[GreaterEqualThan[1/2], 2] @ m
{{1, 3}, {1, 2}, {2, 1}}
take[GreaterEqualThan[0], 2] @ m
{{1, 3}, {1, 2}, {2, 1}, {2, 3}} 
take[GreaterEqualThan[2], 3] @ {Range[5], Range[-3, 2], Reverse @ Range[4, 8]}
{{1, 5}, {1, 4}, {1, 3}, {2, 6}, {3, 1}, {3, 2}, {3, 3}} 
$\endgroup$
6
$\begingroup$

TakeLargest is the function you are looking for. And then Select to get the numbers above 1/2:

m = {{1, 2, 3}, {3, -2, 1/3}};
t = TakeLargest[#, 2] & /@ m
sel=Select[# > 1/2 &] /@ t

(*{{3, 2}, {3}}*)

And then finally the positions. We first determine the position inside sel and then prepend the row number:

pos = Flatten /@ MapThread[Function[{x, y}, Position[x, #] & /@ y], {m, sel}]
MapIndexed[Function[{x, y}, {Sequence @@ y, #} & /@ x], pos]

(* {{{1, 3}, {1, 2}}, {{2, 1}}} *)
$\endgroup$
2
  • $\begingroup$ OP is looking for positions of these, not the actual values. $\endgroup$
    – Nasser
    Feb 16, 2021 at 9:33
  • $\begingroup$ Just give me a minute, I am still writing. $\endgroup$ Feb 16, 2021 at 9:41
4
$\begingroup$

We can also use the new PositionLargest (since 13.2)

m = {{1, 2, 3}, {3, -2, 1/3}};

Get positions:

p = Flatten @ PositionLargest[#, Min[2, Count[#, u_ /; u > 0.5]]] & /@ m

{{3, 2}, {1}}

Index them:

Flatten[#, 1] & @ MapIndexed[Thread[{#2[[1]], #1}] &] @ p

{{1, 3}, {1, 2}, {2, 1}}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.