Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I have a list representing a 2D matrix, such as this 3 ⨉ 2 one:

{{2.1, 1.01}, {0.01, 7.2}, {7.8, 2.0}}

Does anyone know how to find the minimum of each row, ideally outputting a new list of 1's where the row minimums are in the original matrix and 0's for all other elements? i.e.

{{0, 1}, {1, 0}, {0, 1}}

The answer should work for any m ⨉ n list.

share|improve this question

6 Answers 6

up vote 7 down vote accepted

Another way :

f = UnitStep[ Min @ # - #]&;
f /@ {{2.1, 1.01}, {0.01, 7.2}, {7.8, 2.0}}
{{0, 1}, {1, 0}, {0, 1}}
share|improve this answer
    
+1, I like this the best –  acl Dec 21 '12 at 0:28
    
@acl Thanks, your method is also reasonable, +1. –  Artes Dec 21 '12 at 0:36
    
I came up with 1 - Unitize[Min@# - # & /@ a] myself. Yours is cleaner. +1 –  Mr.Wizard Dec 21 '12 at 1:16

There is one way:

list={{2.1, 1.01}, {0.01, 7.2}, {7.8, 2.0}}
SetAttributes[Equal,Listable]
#==Min[#]&/@list//Boole
(*{{0,1},{1,0},{0,1}}*)

Or, as suggested by @swish, without change attributes:

list={{2.1, 1.01}, {0.01, 7.2}, {7.8, 2.0}}
Thread[# == Min[#]] & /@ list // Boole
(*{{0,1},{1,0},{0,1}}*)
share|improve this answer
2  
Maybe better Thread[# == Min[#]] & /@ list // Boole instead of setting Listable attribute? –  swish Dec 20 '12 at 23:55
    
@swish nice tip! Updated –  Murta Dec 20 '12 at 23:57
    
This is quite neat ;) +1 –  Vitaliy Kaurov Dec 20 '12 at 23:59
1  
nice (and first :) ) –  acl Dec 21 '12 at 0:28

Since we have a pile of methods but no timings I'll perform that test.

First my own:

mrwizard[a_] := UnitStep[Min /@ a - a]

And other functions as I'll use them:

murta[list_] := Thread[# == Min[#]] & /@ list // Boole

acl[mat_] := SparseArray[Position[#, Min[#]] -> 1, Length@#] & /@ mat // Normal

artes[a_] := UnitStep[ Min @ # - #]& /@ a

swish[a_] := Thread[KroneckerDelta[Min@#, #]] & /@ a

I leave out RiemannZeta's method as it only works on rows of length two, and therefore does not meet the question specification.

SetAttributes[timeAvg, HoldFirst]

timeAvg[func_] := 
  Do[If[# > 0.3, Return[#/5^i]] & @@ Timing@Do[func, {5^i}], {i, 0, 15}]

funcs = {murta, acl, artes, swish, mrwizard};

Many short rows:

a = RandomReal[{-9, 9}, {150000, 3}];

timeAvg[#@a] & /@ funcs
{0.452, 1.42, 0.515, 0.468, 0.04184}
SameQ @@ (#@a & /@ funcs)

True

Long rows:

a = RandomReal[{-9, 9}, {100, 30000}];

timeAvg[#@a] & /@ funcs
{0.827, 0.421, 0.02496, 1.108, 0.1216}
SameQ @@ (#@a & /@ funcs)

True

From this it appears that Artes' method is fastest on a matrix with a limited number of long rows, and my method which is based on his is fastest on a matrix with many short rows.

share|improve this answer
    
Comparative analysis became your speciality +1. –  Artes Dec 21 '12 at 2:27
    
I decided not to look and ended up with the same answer as you, +1 –  Rojo Dec 21 '12 at 2:47
    
Great analysis - now we have elegance and empirical evidence for the best method. (Maybe I jumped the gun when awarding the solution, but it was late and my requirements were related to a small list!) –  rnoodle Dec 21 '12 at 12:12
1  
I add my timings since they are a bit different (perhaps some random issue) for a = RandomReal[{-9, 9}, {150000, 3}]; timeAvg[#@a] & /@ funcs only your approach was better than mine : {1.201208, 3.915625, 0.102961, 1.341609, 0.0411843}, while for a = RandomReal[{-9, 9}, {100, 30000}]; timeAvg[#@a] & /@ funcs returned {2.277615, 2.496016, 0.078000, 2.839218, 0.121681}. –  Artes Dec 21 '12 at 12:48
    
@rnoodle You can always change your Accept. –  Mr.Wizard Dec 21 '12 at 13:28

If mat = {{2.1, 1.01}, {0.01, 7.2}, {7.8, 2.0}} then

SparseArray[Position[#, Min[#]] -> 1, Length@#] & /@ mat // Normal
(*{{0, 1}, {1, 0}, {0, 1}}*)

If the minimal element appears twice, this returns 1 in both places. Note the Normal isn't necessary, it's for presentation purposes.

share|improve this answer

One more:

m = {{2.1, 1.01}, {0.01, 7.2}, {7.8, 2.0}};
Thread[KroneckerDelta[Min@#, #]] & /@ m
(*{{0, 1}, {1, 0}, {0, 1}}*)

Or:

Thread /@ KroneckerDelta /@ (Min /@ m - m)

We can get rid of Thread:

SetAttributes[KroneckerDelta, Listable]
KroneckerDelta[Min@#, #] & /@ m
KroneckerDelta /@ (Min /@ m - m)
share|improve this answer
m = {{2.1, 1.01}, {0.01, 7.2}, {7.8, 2.0}};
Ordering /@ -m - 1

(* {{0, 1}, {1, 0}, {0, 1}} *)
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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