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$ Commented Feb 16, 2021 at 9:33
  • $\begingroup$ Just give me a minute, I am still writing. $\endgroup$ Commented 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$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.