3
$\begingroup$

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?

$\endgroup$
2
  • 4
    $\begingroup$ Welcome to the Mathematica Stack Exchange. Please load a representative sample of your list; say 50 entries. You can copy code directly from the input cell and paste it into the Edit window. There is the { } icon there to format it. $\endgroup$
    – Syed
    Commented May 13, 2022 at 12:05
  • 1
    $\begingroup$ I strongly suspect that this question has been misinterpreted (by me at least). Can you post a sample data set, as Syed has suggested? For example, does your data consist ONLY of "high", "low" and "medium" string-values, or are these terms merely descriptions of real of integer entries? $\endgroup$
    – user1066
    Commented May 14, 2022 at 9:45

3 Answers 3

10
$\begingroup$

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 *)
$\endgroup$
5
$\begingroup$
Permute[SortBy[Gather[list],First], Cycles[{{2,1,3}}]]//Flatten

where

 list = RandomChoice[{"medium","low", "high"}, 100];
$\endgroup$
1
  • 1
    $\begingroup$ +1 Wow! That approach is fast! $\endgroup$
    – JimB
    Commented May 13, 2022 at 22:36
2
$\begingroup$
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"}

$\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.