3
$\begingroup$

I have a list of rules such as

listofrules = {{1, 1, 2, 5, 14} -> 1, {1, 1, 2, 7, 12} -> 1, {137, 1, 2, 6, 16} -> 1, {137, 1, 2, 8, 13} -> 1, {273, 1, 2, 3, 5} -> 1, {273, 1, 2, 3, 7} -> 2, {273, 1, 2, 9, 12} -> 1, {273, 1, 2, 9, 14} -> -2, {409, 1, 2, 3, 6} -> 1, {409, 1, 2, 3, 8} -> 2, {409, 1, 2, 9, 13} -> -1, {409, 1, 2, 9, 16} -> 2, {545, 1, 2, 4, 5} -> 1, {577,1,1,1,1} -> -3 ...... , {9520, 16, 16, 13, 16} -> 2, {9520, 16, 16, 1, 1} -> 2, {9520, 16, 16, 2, 2} -> -2, {9520, 16, 16, 5, 5} -> -4, {9520, 16, 16, 6, 6} -> 3, {9520, 16, 16, 7, 7} -> -12, {9520, 16, 16, 8, 8} -> -1, {9520, 16, 16, 10, 10} -> -1, {9520, 16, 16, 12, 12} -> -4, {9520, 16, 16, 13, 13} -> 3, {9520, 16, 16, 14, 14} -> -12, {9520, 16, 16, 15, 15} -> 4, {9520, 16, 16, 16, 16} -> -1} 

I want to sort it, ordering the last four elements of the LHS in growing order, irrespective of the first element.

For example, I want all the rules {#,1,1,1,1} -> # first, then all the rules {#,1,1,1,2} -> # etc...

How can I do that in an efficient way?

$\endgroup$

3 Answers 3

4
$\begingroup$

Try

listofrules={ {1,1,2,5,14}->1,{1,1,2,7,12}->1,{137,1,2,6,16}->1,{137,1,2,8,13}->1, {273,1,2,3,5}->1,{273,1,2,3,7}->2,{273,1,2,9,12}->1,{273,1,2,9,14}->-2, {409,1,2,3,6}->1,{409,1,2,3,8}->2,{409,1,2,9,13}->-1,{409,1,2,9,16}->2, {545,1,2,4,5}->1,{577,1,1,1,1}->-3,{9520,16,16,13,16}->2,{9520,16,16,1,1}->2, {9520,16,16,2,2}->-2,{9520,16,16,5,5}->-4,{9520,16,16,6,6}->3, {9520,16,16,7,7}->-12,{9520,16,16,8,8}->-1,{9520,16,16,10,10}->-1, {9520,16,16,12,12}->-4,{9520,16,16,13,13}->3,{9520,16,16,14,14}->-12, {9520,16,16,15,15}->4,{9520,16,16,16,16}->-1}; SortBy[listofrules,#[[1,{2,3,4,5}]]&] 

which extracts the items that you want to sort by and thus returns

{{577, 1, 1, 1, 1} -> -3, {273, 1, 2, 3, 5} -> 1, {409, 1, 2, 3, 6} -> 1, {273, 1, 2, 3, 7} -> 2, {409, 1, 2, 3, 8} -> 2, {545, 1, 2, 4, 5} -> 1, {1, 1, 2, 5, 14} -> 1, {137, 1, 2, 6, 16} -> 1, {1, 1, 2, 7, 12} -> 1, {137, 1, 2, 8, 13} -> 1, {273, 1, 2, 9, 12} -> 1, {409, 1, 2, 9, 13} -> -1, {273, 1, 2, 9, 14} -> -2, {409, 1, 2, 9, 16} -> 2, {9520, 16, 16, 1, 1} -> 2, {9520, 16, 16, 2, 2} -> -2, {9520, 16, 16, 5, 5} -> -4, {9520, 16, 16, 6, 6} -> 3, {9520, 16, 16, 7, 7} -> -12, {9520, 16, 16, 8, 8} -> -1, {9520, 16, 16, 10, 10} -> -1, {9520, 16, 16, 12, 12} -> -4, {9520, 16, 16, 13, 13} -> 3, {9520, 16, 16, 13, 16} -> 2, {9520, 16, 16, 14, 14} -> -12, {9520, 16, 16, 15, 15} -> 4, {9520, 16, 16, 16, 16} -> -1} 

For this particular choice of the items to sort by

SortBy[listofrules,Rest[#[[1]]]&] 

will also work. And there are probably several other ways of selecting the desired four elements.

$\endgroup$
3
  • $\begingroup$ Thank you, it works! Can you explain me what #[[1,{2,3,4,5}]]&] does, please? $\endgroup$ Commented Aug 4, 2020 at 8:39
  • 2
    $\begingroup$ Sure. Part of the culture of Mathematica is to turn lots of stuff into punctuation characters. Stuff followed by & is a function, but we just use it and don't give it any name, look at the documentation reference.wolfram.com/language/ref/Function.html This function is going to have a single argument and that is indicated by # which will be any one of the items in your list. Then #[[1]] will extract the first part of your rule. And #[[1,{2,3,4,5}]] is going to extract the 2nd through 5th items out of that first part. SortBy uses this to extract the items to sort by. Is that enough? $\endgroup$ Commented Aug 4, 2020 at 8:53
  • $\begingroup$ Perhaps compare this f[r_]:=r[[1,{2,3,4,5}]]; SortBy[listofrules,f] to the #& version and see if that helps you a little. You can also search the help system for things like [[ and that will provide some explanation on how this is extracting the desired bits. $\endgroup$ Commented Aug 4, 2020 at 17:08
4
$\begingroup$
#[[Ordering[#[[All, 1, 2 ;;]]]]] & @ listofrules 
{{577, 1, 1, 1, 1} -> -3, {273, 1, 2, 3, 5} -> 1, {409, 1, 2, 3, 6} -> 1, {273, 1, 2, 3, 7} -> 2, {409, 1, 2, 3, 8} -> 2, {545, 1, 2, 4, 5} -> 1, {1, 1, 2, 5, 14} -> 1, {137, 1, 2, 6, 16} -> 1, {1, 1, 2, 7, 12} -> 1, {137, 1, 2, 8, 13} -> 1, {273, 1, 2, 9, 12} -> 1, {409, 1, 2, 9, 13} -> -1, {273, 1, 2, 9, 14} -> -2, {409, 1, 2, 9, 16} -> 2, {9520, 16, 16, 1, 1} -> 2, {9520, 16, 16, 2, 2} -> -2, {9520, 16, 16, 5, 5} -> -4, {9520, 16, 16, 6, 6} -> 3, {9520, 16, 16, 7, 7} -> -12, {9520, 16, 16, 8, 8} -> -1, {9520, 16, 16, 10, 10} -> -1, {9520, 16, 16, 12, 12} -> -4, {9520, 16, 16, 13, 13} -> 3, {9520, 16, 16, 13, 16} -> 2, {9520, 16, 16, 14, 14} -> -12, {9520, 16, 16, 15, 15} -> 4, {9520, 16, 16, 16, 16} -> -1} 

This should be faster than SortBy for long lists.

$\endgroup$
2
  • $\begingroup$ How come two # and one &? How should I think about that? $\endgroup$ Commented Aug 4, 2020 at 15:33
  • 1
    $\begingroup$ @PaulCommentary, alternatively, we can define the function #[[Ordering[#[[All, 1, 2 ;;]]]]] & as foo[x_] := x[[Ordering[x[[All, 1, 2 ;;]]]]] and use it as foo[listofrules]. $\endgroup$ Commented Aug 4, 2020 at 15:42
2
$\begingroup$

Another possibility using operator forms (and avoiding pure functions) is:

SortBy[listofrules, Rest @* First] 

{{577, 1, 1, 1, 1} -> -3, {273, 1, 2, 3, 5} -> 1, {409, 1, 2, 3, 6} -> 1, {273, 1, 2, 3, 7} -> 2, {409, 1, 2, 3, 8} -> 2, {545, 1, 2, 4, 5} -> 1, {1, 1, 2, 5, 14} -> 1, {137, 1, 2, 6, 16} -> 1, {1, 1, 2, 7, 12} -> 1, {137, 1, 2, 8, 13} -> 1, {273, 1, 2, 9, 12} -> 1, {409, 1, 2, 9, 13} -> -1, {273, 1, 2, 9, 14} -> -2, {409, 1, 2, 9, 16} -> 2, {9520, 16, 16, 1, 1} -> 2, {9520, 16, 16, 2, 2} -> -2, {9520, 16, 16, 5, 5} -> -4, {9520, 16, 16, 6, 6} -> 3, {9520, 16, 16, 7, 7} -> -12, {9520, 16, 16, 8, 8} -> -1, {9520, 16, 16, 10, 10} -> -1, {9520, 16, 16, 12, 12} -> -4, {9520, 16, 16, 13, 13} -> 3, {9520, 16, 16, 13, 16} -> 2, {9520, 16, 16, 14, 14} -> -12, {9520, 16, 16, 15, 15} -> 4, {9520, 16, 16, 16, 16} -> -1}

$\endgroup$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.