# Conditional sorting of columns in a matrix

I have a matrix with ten columns, and I want to rearrange these columns with three conditions.

1. Column 1+2n and 2+2n (0<=n=<4) always remain together and in the same order (1+2n before 2+2n). Now we can say that we have five sets of columns, each having two columns.

2. The 2+2n th columns should be sorted with respect to the first elements in them.

3. In case first elements of any two 2+2n columns are same, they should be arranged with respect to the first elements of the corresponding 1+2n columns.

For example if the simplified matrix has only one row {1, 4, 7, 5, 8, 5, 0, 2, 3, 9}, it should be rearranged to {0, 2, 1, 4, 7, 5, 8, 5, 3, 9}.

Thanks for the help!

• Would you say this result looks correct?
– Syed
Oct 13, 2021 at 17:20
• Yes. It is what I want. Oct 13, 2021 at 17:28

Update: A generalization that takes partition sizes, reference row and column sort order for sorting:

ClearAll[partitionedOrderingBy]
partitionedOrderingBy[m_, referenceRow_: 1, partitionSize_: 2, sortOrder_: Automatic] :=
Module[{
partitionedIndices = Partition[Range@Dimensions[m][[2]], partitionSize],
sortFunctions = Table[With[{i = i}, m[[referenceRow, #[[i]]]] &],
{i, sortOrder /. Automatic -> Reverse @ Range @ partitionSize}]},
Flatten @ SortBy[sortFunctions] @ partitionedIndices]


Examples:

SeedRandom[1]
mat = RandomInteger[10, {3, 12}];

MatrixForm @ mat


mat[[All, partitionedOrderingBy[mat]]]


highlightPartitions[m_, partitionSize_: 2] := MapIndexed[
Highlighted[Style[#, 16], Background->ColorData[97]@(Ceiling[#2[[2]]/partitionSize])]&,
m, {2}]

MatrixForm[#, TableHeadings -> {{1, 2, 3}, Range@12}] & @ highlightPartitions[mat]


Sort using default values for arguments:

With[{r = 1},
MatrixForm[highlightPartitions[mat, 2][[All, #]],
TableHeadings -> {Range[3] /. r -> Style[r, 20, Bold, Red], #}] &@
partitionedOrderingBy[mat]]


Use the second row as reference row for sorting:

With[{r = 2},
MatrixForm[highlightPartitions[mat, 2][[All, #]],
TableHeadings -> {Range[3] /. r -> Style[r, 20, Bold, Red], #}] &@
partitionedOrderingBy[mat, r]]


Use the lexical order {1,2} instead of the default {2,1}:

With[{r = 1},
MatrixForm[highlightPartitions[mat, 2][[All, #]],
TableHeadings -> {Range[3] /. r -> Style[r, 20, Bold, Red], #}] &@
partitionedOrderingBy[mat, r, 2, {1, 2}]]


Partition columns into consecutive triples (instead of consecutive pairs):

MatrixForm[#, TableHeadings -> {{1, 2, 3}, Range@12}] & @ highlightPartitions[mat, 3]


Use the default reference row (1) for sorting:

With[{r = 1},
MatrixForm[highlightPartitions[mat, 3][[All, #]],
TableHeadings -> {Range[3] /. r -> Style[r, 20, Bold, Red], #}] &@
partitionedOrderingBy[mat, r, 3]]


Use row 3 as the reference row:

With[{r = 3},
MatrixForm[highlightPartitions[mat, 3][[All, #]],
TableHeadings -> {Range[3] /. r -> Style[r, 20, Bold, Red], #}] &@
partitionedOrderingBy[mat, r, 3]]

MatrixForm @ highlightPartitions[mat, 3][[All, partitionedOrderingBy[mat, 2, 3]]]


Use partition size 4 and first row as reference row:

MatrixForm[#, TableHeadings -> {{1, 2, 3}, Range@12}] &@ highlightPartitions[mat, 4]


With[{r = 1},
MatrixForm[highlightPartitions[mat, 4][[All, #]],
TableHeadings -> {Range[3] /. r -> Style[r, 20, Bold, Red], #}] &@
partitionedOrderingBy[mat, r, 4]]


For input matrix m, Partition the column indices and lexically sort the pairs of indices based on first row elements of m )so that the index pair {pi1, pi2} comes before the pair {pj1, pj2} iff m[[1,pi2]] < m[[1,pj2]] or m[[1,pi2]] == m[[1,pj2]] and m[[1,pi1]] < m[[1,pj1]]):

ClearAll[partitionAndSort]

partitionAndSort[m_] := Module[{
partitionedColumnIndices = Partition[Range @ Dimensions[m][[2]], 2],
lexicalSortFunctions = {m[[1, #[[2]]]] &, m[[1, #[[1]]]] &},
columnsOrdering},
columnsOrdering =  Flatten @ SortBy[lexicalSortFunctions] @ partitionedColumnIndices;
m[[All, columnsOrdering]]]


Example:

SeedRandom[1]
mat = RandomInteger[10, {3, 10}];

MatrixForm @ mat


MatrixForm @ partitionAndSort @ mat