6
$\begingroup$

I would like to sort a matrix in descending order first by the total of each column, then by the total of each row, but without changing their content. For example, if I had:

TableForm[{{0, 0, 1, 1}, {0, 0, 0, 1}, {1, 0, 1, 1}, {1, 1, 1, 1}}, 
 TableHeadings -> {Range[1, 4], Range[1, 4]}]

I want to sort first the columns:

TableForm[{{1, 1, 0, 0}, {1, 0, 0, 0}, {1, 1, 1, 0}, {1, 1, 1, 1}}, 
 TableHeadings -> {Range[1, 4], {"4", "3", "1", "2"}}]

Then the rows:

TableForm[{{1, 1, 1, 1}, {1, 1, 1, 0}, {1, 1, 0, 0}, {1, 0, 0, 0}}, 
 TableHeadings -> {{"4", "3", "1", "2"}, {"4", "3", "1", "2"}}]

The goal is to get as many 1's as possible to the upper-left corner. I added TableHeadings to this mockup of the desired result simply to show the content of the columns/rows remains the same. If there is a better way other than using the Total for each column/row that is fine too. Any help is much appreciated!

$\endgroup$
0

4 Answers 4

5
$\begingroup$

Ordering and Part are applicable to this kind of problem. Reverse is needed below as you want to place larger elements to the upper left rather than lower right.

tab = {{0, 0, 1, 1}, {0, 0, 0, 1}, {1, 0, 1, 1}, {1, 1, 1, 1}};

tab = tab[[All, Reverse @ Ordering[tab ~Total~ {1}]]];

tab[[Reverse @ Ordering[tab ~Total~ {2}]]] // TableForm

Mathematica graphics

(This may not be the most efficient algorithm to achieve your goal.)


I believe this can also be done with one application of Part by computing the Ordering for each level beforehand:

newSort[x_?ArrayQ] :=
  x[[##]] & @@ (Reverse@Ordering[x ~Total~ {#}] & /@ {2, 1})

newSort[tab]

This could be easily extended to greater dimensions by replacing {2, 1} with Range[ArrayDepth@x, 1, -1].

$\endgroup$
2
  • $\begingroup$ I knew about Part, but Ordering was new for me. Thanks @Mr.Wizard! $\endgroup$
    – Pancholp
    Commented Dec 4, 2012 at 12:45
  • $\begingroup$ @Pancholp You're welcome. Please see the update I just made. $\endgroup$
    – Mr.Wizard
    Commented Dec 4, 2012 at 13:05
4
$\begingroup$

Using Sort :

Sort[Transpose[Sort[Transpose[tab], Total[#1] > Total[#2] &]], Total[#1] > Total[#2] &]
$\endgroup$
1
  • $\begingroup$ Thanks @b.gatessucks! This one works well too. $\endgroup$
    – Pancholp
    Commented Dec 4, 2012 at 12:44
1
$\begingroup$

Since V 12.0 there is ReverseSortBy

list = {{0, 0, 1, 1}, {0, 0, 0, 1}, {1, 0, 1, 1}, {1, 1, 1, 1}};

ReverseSort /@ ReverseSortBy[Total] @ list // MatrixForm

enter image description here

$\endgroup$
1
$\begingroup$

Using ReverseSort:

ReverseSort[ReverseSort /@ Transpose[tab]]

(*{{1, 1, 1, 1}, {1, 1, 1, 0}, {1, 1, 0, 0}, {1, 0, 0, 0}}*)
$\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.