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$
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$
  • $\begingroup$ Thank you, it works! Can you explain me what #[[1,{2,3,4,5}]]&] does, please? $\endgroup$ – Hegel19 Aug 4 '20 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$ – Bill Aug 4 '20 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$ – Bill Aug 4 '20 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$
  • $\begingroup$ How come two # and one &? How should I think about that? $\endgroup$ – PaulCommentary Aug 4 '20 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$ – kglr Aug 4 '20 at 15:42
1
$\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$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.