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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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