I have a list with 10.000 entries containing "low", "medium" & "high" data.
It is in random order. How can I sort that to low, medium high?
The idea in the code below is to replace each entry in the list by a number corresponding to the "priority" of that element, and then sorting according to that priority using SortBy
.
Let's first make a small sample list
of such entries. I'm using only 10 elements for readability, but you can apply this to your list unchanged. Note also that I am using lowercase "low"
, "medium"
, "high"
as you have them in the body of the question. If the first letter is uppercase in your list, as you showed in the title of the question, then change the code to reflect that. If they are in a mix of cases, then apply ToLowerCase
to your list beforehand.)
list = RandomChoice[{"low", "medium", "high"}, 10]
(* Out: {low, high, low, medium, low, high, low, medium, low, medium} *)
SortBy[# /. {"low" -> 1, "medium" -> 2, "high" -> 3}&][list]
(* Out: {low, low, low, low, low, medium, medium, medium, high, high} *)
This works fine even at the 10,000 entry scale, but it isn't very efficient because it does the replacements one element at a time. If performance is very important, or if your lists grow in size, then the following less readable but more efficient approach would be better:
list[[Ordering[list /. {"low" -> 1, "medium" ->2, "high" -> 3}]]]
The difference in performance is significant. To see it more clearly, let's make a much bigger list and compare the timings from the two approaches:
biglist = RandomChoice[{"low", "medium", "high"}, 1000000];
(sortby = SortBy[# /. {"low" -> 1, "medium" -> 2, "high" -> 3}&][biglist];) // RepeatedTiming
(* Out: {2.10536, Null} *)
(ordering = biglist[[Ordering[biglist /. {"low" -> 1, "medium" ->2, "high" -> 3}]]];) // RepeatedTiming
(* Out: {0.204152, Null} *)
Let's also check that the two approaches give the same result:
sortby == ordering (* True *)
Permute[SortBy[Gather[list],First], Cycles[{{2,1,3}}]]//Flatten
where
list = RandomChoice[{"medium","low", "high"}, 100];
o = {"low", "medium", "high"};
list = RandomChoice[o, 10];
Using MapIndexed
SortBy[list, ReplaceAll @ MapIndexed[Rule, o]]
{"low", "low", "low", "low", "medium", "medium", "medium", "high", "high", "high"}
Using AssociationThread
SortBy[list, AssociationThread[o, Range @ Length @ o]]
{"low", "low", "low", "low", "medium", "medium", "medium", "high", "high", "high"}
{ }
icon there to format it. $\endgroup$