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

2 Answers 2

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$ Commented Nov 19, 2021 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
    Commented Nov 14, 2021 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.
    Commented Nov 15, 2021 at 21:59
  • $\begingroup$ @M.A. ReplaceAll[Thread[{a, b, c} -> {b, c, a}]][Map[Sort, list]] $\endgroup$ Commented Nov 16, 2021 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.
    Commented Nov 19, 2021 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.
    Commented Nov 19, 2021 at 6:38

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.