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 matrix in as shown, consisting of real numbers and 0. How can I sort it to become out as shown?

in ={
   {0, 0, 3.411, 0, 1.343},
   {0, 0, 4.655, 2.555, 3.676},
   {0, 3.888, 0, 3.867, 1.666}
   };
out ={
   {1.343, 3.411, 0, 0, 0},
   {2.555, 3.676, 4.655, 0, 0},
   {1.666, 3.867, 3.888, 0, 0}
   };

This is related to a question I asked. It is much easier to add the columns by sorting it this way than in previous question, and easier to visualize than trying to take the first non-zero value in a row.

share|improve this question
1  
Re: "consisting of real numbers and 0" -> "Consisting of the humanity and me" –  belisarius Nov 16 '12 at 2:46

6 Answers 6

up vote 6 down vote accepted

The simplest way would be to replace zeros with Null, map Sort onto it and then replace Null with zeros. This works because the default sorting function OrderedQ will place Null at the end, as per your needs.

mat =  {{0, 0, 3.411, 0, 1.343}, {0, 0, 4.655, 2.555, 3.676}, {0, 3.888, 0, 3.867, 1.666}};
Map[Sort, mat /. (0 | 0.) -> Null] /. Null -> 0
(*  1.343   3.411   0       0   0
    2.555   3.676   4.655   0   0
    1.666   3.867   3.888   0   0 *)
share|improve this answer
1  
This is much faster and cleaner than my solution. –  Andy Ross Nov 16 '12 at 2:30
    
@AndyRoss Yours can be made faster simply by making it f[0|0.] = Infinity, since the OP said that it only contains zeros. Right now, it's unnecessarily testing every element (twice) with PossibleZeroQ –  rm -rf Nov 16 '12 at 2:32
1  
Right. But the custom sorting function is going to be much slower regardless. –  Andy Ross Nov 16 '12 at 2:33
1  
Hi @rm -rf like your solution –  sebastian c. Nov 16 '12 at 2:42
1  
I would change "will place Null at the end" by "will place any symbol after any number" –  Rojo Nov 16 '12 at 12:58

You can map Sort over the rows using a custom ordering function which treats 0 as infinity.

data = RandomChoice[{0, 1}, {5, 5}]*RandomReal[{1, 10}, {5, 5}];

f[0|0.]= \[Infinity];
f[x_] := x
Sort[#, f[#1] <= f[#2] &] & /@ data

(*{{6.07883, 7.33113, 0., 0., 0.}, {2.74761, 0., 0., 0., 0.},
   {6.09223, 8.11442, 0., 0., 0.}, {3.16126, 4.72089, 7.72369, 0.,0.}, 
   {9.25964, 0., 0., 0., 0.}}*)
share|improve this answer

Since what you are doing is basically sorting each row, but 0 is treated as highest value. One way is to replace all zeros with Infinity before sorting and changing back after

r = RandomChoice[{0, Random[]}, {3, 5}];
r // MatrixForm

(Sort[#] & /@ (r /. {(0 | 0.) -> Infinity})) /. {Infinity -> 0} // MatrixForm

Output

Edit I like Andy Ross's solution better

share|improve this answer
1  
Btw, you could also do something like RandomChoice[{0, Random[]}, {3, 5}] –  Rojo Nov 16 '12 at 13:30
    
Or if your list is big, a faster solution may be Times@@Through@{RandomReal, RandomChoice}[{0, 1}, {3, 5}], adding //Chop if you care about having integer 0 –  Rojo Nov 16 '12 at 13:39
PadRight[#, Length@in[[1]], 0] & /@ Sort /@ DeleteCases[in, 0 | 0., 2]

=>

{{1.343, 3.411, 0, 0, 0}, {2.555, 3.676, 4.655, 0, 0}, {1.666, 3.867, 3.888, 0, 0}}

share|improve this answer
in = {{0, 0, 3.411, 0, 1.343}, {0, 0, 4.655, 2.555, 3.676}, {0, 3.888,
     0, 3.867, 1.666}};

A possible solution

Sort /@ (in I - Unitize[in]) // Im
share|improve this answer

You might use:

SortBy[#, # /. 0 -> {} &] & /@ in

This works because {} will be placed after atomic elements such as real numbers. If your zeros may not always be precise (head Integer) you may use:

SortBy[#, # /. x_ /; x == 0 -> {} &] & /@ in
share|improve this answer
    
That is a nice one. –  TomD Nov 18 '12 at 9:49

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.