In general SortBy can do pretty much anything that Sort does; in some cases, possibly better or faster. You can find many comparisons on this site if you just search for both function names.
I also disagree with @user21382 that his task could not be expressed elegantly in SortBy
form: not only can it be done, I would actually argue that it could be done even more readably with SortBy
than with Sort
.
User21382 set the task to sort the following data, presented as an association, first by ascending age, then by descending alphabetical order. This can be accomplished using the fact that SortBy
can take a list of functions that are applied in sequence to break ties:
data = {
<|"Name"->"Jill", "Age" -> 23|>,
<|"Name"->"Jack", "Age" -> 55|>,
<|"Name"->"Jen", "Age" -> 55|>,
<|"Name"->"Joe", "Age" -> 23|>
};
SortBy[data,
{
(#["Age"]&), (* by age, ascending *)
(Total@ ToCharacterCode@ ToUpperCase@ #["Name"]&) (* by alpha order, descending *)
}
]
(* Out:
{
<|"Name" -> "Joe", "Age" -> 23|>,
<|"Name" -> "Jill", "Age" -> 23|>,
<|"Name" -> "Jen", "Age" -> 55|>,
<|"Name" -> "Jack", "Age" -> 55|>
}
*)
Here I take advantage of the fact that higher character codes correspond to letters further down in alphabetical order, so ordering by increasing character code effectively gives reverse alphabetical order.
SortBy
also has an operator syntax, i.e. the following two usages are equivalent:
SortBy[data, sortingfunction] == SortBy[sortingfunction] [data]
I find the latter form very readable and highly expressive.
Another interesting property of SortBy
is the fact that it gives ready access to a stable sort function, i.e. a sorting algorithm that maintains the relative order of records with equal values, by using the following syntax:
SortBy[ data, {sortingfunction} ]
In this case, no tie-breaking function is provided, so tied values will be left in the original order. This has been showcased multiple times on the site already, so I will just link to this older answer from StackOverflow that explains the point very nicely.