4
$\begingroup$

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.

$\endgroup$
1
  • 2
    $\begingroup$ Re: "consisting of real numbers and 0" -> "Consisting of the humanity and me" $\endgroup$ Commented Nov 16, 2012 at 2:46

7 Answers 7

6
$\begingroup$

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 *) 
$\endgroup$
6
  • 1
    $\begingroup$ This is much faster and cleaner than my solution. $\endgroup$ Commented Nov 16, 2012 at 2:30
  • $\begingroup$ @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 $\endgroup$ Commented Nov 16, 2012 at 2:32
  • 1
    $\begingroup$ Right. But the custom sorting function is going to be much slower regardless. $\endgroup$ Commented Nov 16, 2012 at 2:33
  • 1
    $\begingroup$ Hi @rm -rf like your solution $\endgroup$ Commented Nov 16, 2012 at 2:42
  • 1
    $\begingroup$ I would change "will place Null at the end" by "will place any symbol after any number" $\endgroup$ Commented Nov 16, 2012 at 12:58
6
$\begingroup$

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.}}*) 
$\endgroup$
5
$\begingroup$

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

$\endgroup$
2
  • 1
    $\begingroup$ Btw, you could also do something like RandomChoice[{0, Random[]}, {3, 5}] $\endgroup$ Commented Nov 16, 2012 at 13:30
  • $\begingroup$ 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 $\endgroup$ Commented Nov 16, 2012 at 13:39
2
$\begingroup$
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 
$\endgroup$
2
$\begingroup$

Another possibility:

MapApply[in[[##]]&]@MapIndexed[{First@#2,#1}&,(Ordering/@Replace[in, 0->\[Infinity],2])] (* { {1.343,3.411,0,0,0}, {2.555,3.676,4.655,0,0}, {1.666,3.867,3.888,0,0} } *) 

Original Answer

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} } *) 
$\endgroup$
1
$\begingroup$

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 
$\endgroup$
1
  • $\begingroup$ That is a nice one. $\endgroup$ Commented Nov 18, 2012 at 9:49
1
$\begingroup$

Define your own ordering function:

f[_, 0] := 1 f[0, _] := -1 f[x_, y_] := x <= y Sort[#, f] & /@ in // MatrixForm 

enter image description here

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