I was surprised to discover that Mathematica does not sort lists-of-lists (LLs) lexicographically by default. For example, applying Sort
to {{1, 2}, {3}}
, which is already lexicographically ordered, destroys this order, producing {{3}, {1, 2}}
.
Is there a standard Mathematica function, or idiom, for lexicographically ordering a LL?
EDIT: If I were to roll my own, I'd implement a lexicographic comparator function, to be passed as the second argument to Sort
:
cmpLLs[_][{}, b_List] := True;
cmpLLs[_][a_List, {}] := False;
cmpLLs[by_][a_List, b_List] :=
Module[{va = by[First[a]], vb = by[First[b]]},
If[va == vb, cmpLLs[Rest[a], Rest[b]], va < vb]
];
cmpLLs[a_List, b_List] := cmpLLs[Identity][a, b];
(* test borrowed from Leonid Shifrin's answer *)
test = {{3}, {7}, {4, 6, 2}, {7, 7, 6}, {10, 3, 9}, {6, 7, 9}, {1, 7, 7}};
Sort[test, cmpLLs]
(* {{1, 7, 7}, {3}, {4, 6, 2}, {6, 7, 9}, {7}, {7, 7, 6}, {10, 3, 9}} *)
Sort[test, cmpLLs[Plus]] (* just for giggles *)
(* {{1, 7, 7}, {3}, {4, 6, 2}, {6, 7, 9}, {7}, {7, 7, 6}, {10, 3, 9}} *)
Sort[test, cmpLLs[Minus]]
(* {{10, 3, 9}, {7}, {7, 7, 6}, {6, 7, 9}, {4, 6, 2}, {3}, {1, 7, 7}} *)
Not a stack-friendly implementation, I admit...
ToString
before ordering:ToExpression /@ Sort[ToString /@ {{3}, {1, 2}}]
(or roll your own ordering function). $\endgroup$Sort
on lists sorting by the size of the sub-list first, and only applying lexicographic sort for equal-size lists. This is in fact documented. $\endgroup$Sort
, under details, fourth bullet point: " usually orders expressions by putting shorter ones first, and then comparing parts in a depth-first manner. ". $\endgroup$Ordering
is less likely to be slow e.g. from deep recursion in a depth first search. $\endgroup$