2
$\begingroup$

I have this matrix...

mat = Table[{k, 0}, {k, 0, limit}];

After a series of dynamic iterative operations, some of the 0 initialized entries (i.e., those of the 2nd column of mat, i.e., mat[[All, 2]]) are replaced w/ positive integers, e.g.,

mat = {{0,78},{1,0},{2,0},{3,11},{4,11},{5,11},...,{limit,0}}

I realize that there are several standard ways for retrieving the nth minimum value of mat[[All, 2]] but, since mat has so many 0s, they do not help me.

I am looking for a standard/elegant/efficient way to find the nth UNIQUE min value of mat, along w/ its associated row index, e.g., if limit = 6 & I wanted to find the 2nd min-value/index pair, executing...

Print[UniqueMin[mat[[All, 2]], 2]];

would output...

{4,11}

Bc 11 was the 2nd smallest unique value in mat & row 4 was where it 1st occurred.

$\endgroup$
2
  • $\begingroup$ Why {4,11}, not {3,11}? $\endgroup$
    – corey979
    Commented Apr 15, 2019 at 6:25
  • $\begingroup$ @corey979 Bc Mathematica starts index @ 1, not 0. You'd be right, if I was asking for the associated row value, but I asked for the associated row index. $\endgroup$
    – Landon
    Commented Apr 15, 2019 at 6:39

4 Answers 4

3
$\begingroup$
UniqueMin[list_?VectorQ, n_Integer?Positive] :=
 Module[{min = Union[list][[n]]},
  {Position[list, min][[1, 1]], min}]

mat = {{0, 78}, {1, 0}, {2, 0}, {3, 11}, {4, 11}, {5, 11}};

UniqueMin[mat[[All, 2]], 2]

(* {4, 11} *)
$\endgroup$
1
$\begingroup$
mat = {{0, 78}, {1, 0}, {2, 0}, {3, 11}, {4, 11}, {5, 11}};

Using Sort and FirstPosition:

{FirstPosition[mat, {_, #}][[1]], #} &@Sort[Union[mat[[All, 2]]]][[2]]

(*{4, 11}*)
$\endgroup$
1
$\begingroup$
mat = {{0, 78}, {1, 0}, {2, 0}, {3, 11}, {4, 11}, {5, 11}};

Using TakeSmallestBy

Last @ TakeSmallestBy[Union[mat] -> {"Index", "Element"}, First, 2]

{2, {1, 0}}

Revision

As Daniel Lichtblau commented the above answer is wrong. A correct answer, using his suggested PositionSmallest, would be:

{#, mat[[#, -1]]} & @ PositionSmallest[mat[[All, 2]], 2][[-1, 1]]

{4, 11}

$\endgroup$
2
  • 2
    $\begingroup$ The position to be found her eis actually 4 though. In[1135]:= mat = {{0, 78}, {1, 0}, {2, 0}, {3, 11}, {4, 11}, {5, 11}, {33, 0}}; posn = First[Last[PositionSmallest[mat[[All, 2]], 2]]] Out[1136]= 4 $\endgroup$ Commented Feb 2 at 0:53
  • $\begingroup$ Thank you, Daniel, see revision $\endgroup$
    – eldo
    Commented Feb 2 at 7:31
0
$\begingroup$

An alternative approach would use PositionIndex followed by KeySort

The variants below differ in either accessing the parts of the result or using a pattern match (which is slightly slower)

(* version 1*)
Clear[UniqueMin]

UniqueMin[list_?VectorQ, n_Integer?Positive] := With[
  {entry = Take[#, {n}]& @ KeySort @ PositionIndex @ list},
  {entry[[1, 1]], Keys[entry][[1]]}]

UniqueMin[mat[[All, 2]], 2]
(* {4, 11} *)


(* version 2 *)
Clear[UniqueMin]

UniqueMin[list_?VectorQ, n_Integer?Positive] := 
 With[{entry = Take[#, {n}]& @ KeySort @ PositionIndex @ list}, 
  Replace[entry, Association[Rule[x_, List[y_, ___]]] :> {y, x}]]

UniqueMin[mat[[All, 2]], 2]
(* {4, 11} *)

```
$\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.