Sort lists according to the order of another
You can use combination of Part
and Ordering
as
list1[[ Ordering @ list2 ]]
to sort list1
in the order of list2
.
Examples:
{list1, list2, list3} = {{1, 3, 2}, {a, b, c}, {x, y, z}};
list2[[ Ordering @ list1 ]]
gives
{a, c, b}
and
list3[[ Ordering @ list1 ]]
gives
{x, z, y}
EDIT: Using with lists of lists, to sort the entire array based on the first list:
list = {list1, list2, list3};
list[[ All, Ordering @ list[[1]] ]]
gives
{{1, 2, 3}, {a, c, b}, {x, z, y}}
But ... as I just noticed, this is already covered in @Mr.Wizard's answer long before my edit.
lists = {list1, list2, list3} = {{1, 3, 2}, {a, b, c}, {x, y, z}};
Another option
SortBy[lists\[Transpose], First]\[Transpose]
{{1, 2, 3}, {a, c, b}, {x, z, y}}
Ordering
and Part
is more efficient than SortBy
and Transpose
and it can also be done in one pass as I will demonstrate.
I create three lists of different type as described in the question:
a = RandomInteger[999, 500];
b = RandomReal[1, 500];
c = CharacterRange["a", "z"] ~RandomChoice~ 500;
I use the timeAvg
function for testing:
SortBy[{a, b, c}\[Transpose], First]\[Transpose] // timeAvg
{a, b, c}[[All, Ordering@a]] // timeAvg
0.00027456
0.000026944
As can be seen second method is more than an order of magnitude faster on this data.
It is noteworthy that these two forms as shown do not perform the same operation because SortBy[list, func]
is not a stable sort. Observe:
lists = {{8, 8, 6, 3, 7},
{"i", "e", "f", "b", "m"},
{"q", "x", "u", "w", "z"}};
SortBy[lists\[Transpose], First]\[Transpose]
lists[[All, Ordering @ First @ lists]]
{{3, 6, 7, 8, 8}, {"b", "f", "m", "e", "i"}, {"w", "u", "z", "x", "q"}} {{3, 6, 7, 8, 8}, {"b", "f", "m", "i", "e"}, {"w", "u", "z", "q", "x"}}
You can see see that SortBy
has swapped the positions of "i"
/"e"
and "q"
/"x"
in the lists so it is not a minimal reordering. This can be corrected however with a different syntax for SortBy
:
SortBy[lists\[Transpose], {First}]\[Transpose]
{{3, 6, 7, 8, 8}, {"b", "f", "m", "i", "e"}, {"w", "u", "z", "q", "x"}}
This syntax also speeds up SortBy
, but not enough to be competitive with Ordering
:
SortBy[{a, b, c}\[Transpose], {First}]\[Transpose] // timeAvg
0.0001248