4
$\begingroup$

I have a nested list like this one:

list={{{a,1},{b,3},{c,5}},{{b,1},{c,3},{a,5}},{{c,1},{b,3},{a,5}},{{a,1},{c,3},{b,5}}}

Now I need to sort the list such that the order within a row is always {{a,..},{b,..},{c,..}}. Put differently: the order of the first elements within the sublists should always be a, b and then c.

$\endgroup$
1
3
$\begingroup$
ClearAll[sortLike]
sortLike[refcolumn_, orderlike_] := 
 Map[#[[Ordering[#[[All, refcolumn]]][[Ordering @ Ordering @ orderlike]]]] &]

Examples:

list = {{{a, 1}, {b, 3}, {c, 5}}, {{b, 1}, {c, 3}, {a, 5}}, 
   {{c, 1}, {b, 3}, {a, 5}}, {{a, 1}, {c, 3}, {b, 5}}};


sortLike[1, {a, b, c}]@list // Column

enter image description here

sortLike[1, {b, a, c}]@list // Column

enter image description here

sortLike[2, {1, 2, 10}]@list // Column

enter image description here

sortLike[2, {5, 1, 3}]@list // Column

enter image description here

The argument orderlike can be given alternative ways to get the same result:

Multicolumn[Labeled[Column[sortLike[1, #]@list], 
    Row[{"orderlike: ", Style[#, ShowStringCharacters -> True]}], Top] & /@ 
 {{c, a, b}, {"c", "a", "b"}, {"FOO", "BAR", "BUZZ"}, {3, 1, 2}, 
  {100, 0, 25}, foo[10, 1, 9]}, 3,
 Dividers -> All, Alignment -> Center]

enter image description here

$\endgroup$
1
  • $\begingroup$ Nice answer! That way it is general. $\endgroup$ Nov 19 '21 at 19:42
6
$\begingroup$

Something like the following:

Map[Sort[#] &, list]
(*{{{a, 1}, {b, 3}, {c, 5}}, {{a, 5}, {b, 1}, {c, 3}}, {{a, 5}, {b, 3}, {c, 1}}, {{a, 1}, {b, 5}, {c, 3}}}*)

A first approximation:

MyOrderList[list_List, order_?(Positive[#] && Element[#, Integers] &)] := 
Block[{slist, perm, mylist},
slist := Map[Sort, list];
perm = Mean[Map[Composition[Length, Permutations[#] &], slist]];
mylist := 
Table[Table[Extract[Select[Tuples[slist[[i]], Length[slist[[i]]]], 
ContainsAll[#, slist[[i]]] &], j], {i, 1, Length[slist]}], {j, 1, perm}][[order]];
Return[If[order <= perm, mylist, HoldForm[MyOrderList]]];
];

Tests:

MyOrderList[list, 1]
(*{{{a, 1}, {b, 3}, {c, 5}}, {{a, 5}, {b, 1}, {c, 3}}, {{a, 5}, 
  {b, 3}, {c, 1}}, {{a, 1}, {b, 5}, {c, 3}}}*)
MyOrderList[list, 2]
(*{{{a, 1}, {c, 5}, {b, 3}}, {{a, 5}, {c, 3}, {b, 1}}, {{a, 5}, 
  {c, 1}, {b, 3}}, {{a, 1}, {c, 3}, {b, 5}}}*)
MyOrderList[list, 3]
(*{{{b, 3}, {a, 1}, {c, 5}}, {{b, 1}, {a, 5}, {c, 3}}, {{b, 3}, 
  {a, 5}, {c, 1}}, {{b, 5}, {a, 1}, {c, 3}}}*)
MyOrderList[list,4]
(*{{{b, 3}, {c, 5}, {a, 1}}, {{b, 1}, {c, 3}, {a, 5}}, {{b, 3}, 
  {c, 1}, {a, 5}}, {{b, 5}, {c, 3}, {a, 1}}}*)
MyOrderList[list,5]
(*{{{c, 5}, {a, 1}, {b, 3}}, {{c, 3}, {a, 5}, {b, 1}}, {{c, 1}, 
  {a, 5}, {b, 3}}, {{c, 3}, {a, 1}, {b, 5}}}*)
MyOrderList[list,6]
(*{{{c, 5}, {b, 3}, {a, 1}}, {{c, 3}, {b, 1}, {a, 5}}, {{c, 1}, 
  {b, 3}, {a, 5}}, {{c, 3}, {b, 5}, {a, 1}}}*)

Another approach using the idea of @cvgmt:

  MyOrderList[list_List, order_List] := 
  Block[{slist, sorder, ordering, mylist},
  slist := Map[Sort, list];
  ordering := 
  Extract[Permute[Ordering[Sort[order]], Ordering[#]] & /@ 
  Permutations[order], {1}];(*@cvgmt*)
  mylist := Table[slist[[i]][[ordering]], {i, 1, Length[slist]}];
  Return[mylist];
   ];

Test:

MyOrderList[list, {b, c, a}]
(*{{{b, 3}, {c, 5}, {a, 1}}, {{b, 1}, {c, 3}, {a, 5}}, {{b, 3}, 
  {c, 1}, {a, 5}}, {{b, 5}, {c, 3}, {a, 1}}}*)

Another approach using the idea of @kglr:

 MyOrderList[list_List, order_List] := 
 Block[{slist, sorder, ordering, mylist},
 slist := Map[Sort, list];
 ordering := 
 Extract[Map[Ordering@*Ordering, Permutations[order]], {1}];(*@kglr*)
 mylist := Table[slist[[i]][[ordering]], {i, 1, Length[slist]}];
 Return[mylist];
   ];

Test:

MyOrderList[list, {c, a, b}]
(*{{{c, 5}, {a, 1}, {b, 3}}, {{c, 3}, {a, 5}, {b, 1}}, {{c, 1}, 
  {a, 5}, {b, 3}}, {{c, 3}, {a, 1}, {b, 5}}}*)
$\endgroup$
6
  • 7
    $\begingroup$ This can be abbreviated by noting that Map[Sort[#] &, list] === Map[Sort, list] === Sort /@ list $\endgroup$
    – Bob Hanlon
    Nov 14 '21 at 22:04
  • $\begingroup$ This is all very nice but now lets assume I want the order to be {{b,..},{c,..},{a,..}}?? Is there a way to define a fixed predefined order? I'm sorry my question was not exact enough. I used a, b and c to keep it very simple.. e.g. the first elements could also be some text strings... $\endgroup$
    – M.A.
    Nov 15 '21 at 21:59
  • $\begingroup$ @M.A. ReplaceAll[Thread[{a, b, c} -> {b, c, a}]][Map[Sort, list]] $\endgroup$ Nov 16 '21 at 4:29
  • 1
    $\begingroup$ @E.Chan-López This changes the structure of the list!! Besides this, your code does not work if you replace a, b,c with strings... $\endgroup$
    – M.A.
    Nov 19 '21 at 6:29
  • $\begingroup$ @E.Chan-López: the first code in your answer produces NOT the same result as your function $\endgroup$
    – M.A.
    Nov 19 '21 at 6:38

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.