Qiang Li
Qiang Li

Reputation: 10865

Sort a list of lists based on alphabetical order of inner list elements in Mahtematica

I have a list of lists with inner lists possibly of variable lengths. I need to sort the outer list based on the alphabetical order of the inner list elements. For example, given a list of

{{0, 0, 7}, {5, 0, 2, 3}, {0, 0, 10, 0}, {0, 6, 2}, {5, 1, 2}, {0, 3, 6, 1, 4}}

I want the output after Sort to be

{{0, 0, 10, 0}, {0, 0, 7}, {0, 3, 6, 1, 4}, {0, 6, 2}, {5, 0, 2, 3}, {5, 1, 2}}

I just do not know how to handle the variable lengths of inner lists in order to write a comparison function. Please help.

Edit

BTW, the original list is a numerical one.

Edit 2

For example, I have a list:

{{0, 0, 7}, {5, 0, 2, 3}, {0, 0, 11, 0}, {0, 0, 1, 12}, {0, 6, 2}, {5, 1, 2}, {0, 3, 6, 1, 4}}

The output should be:

{{0, 0, 1, 12}, {0, 0, 11, 0}, {0, 0, 7}, {0, 3, 6, 1, 4}, {0, 6, 2}, {5, 0, 2, 3}, {5, 1, 2}}

The reason is that 1 is lexically less than 11, which is less than 7.

Upvotes: 3

Views: 1622

Answers (3)

Mr.Wizard
Mr.Wizard

Reputation: 24336

alphaSort = #[[ Ordering @ Map[ToString, PadRight@#, {2}] ]] &;

This works by preparing the data for the default Ordering sort, and then using that order to sort the original list.

In this case, padding all of the lists to the same length keeps this Sort property from interfering:

Sort usually orders expressions by putting shorter ones first, and then comparing parts in a depth-first manner.

ToString is used to get an alphabetical order rather than a numeric one.

Upvotes: 2

You can set up a lexciographic comparator like this:

lexComp[_, {}] := False;
lexComp[{}, _] := True;
lexComp[{a_, as___}, {b_, bs___}] := a < b || a == b && lexComp[{as}, {bs}];

You can then sort using that to get the desired effect:

Sort[{{0, 0, 7}, {5, 0, 2, 3}, {0, 0, 10, 0}, {0, 6, 2}, {5, 1, 2}, {0, 3, 6, 1, 4}}, lexComp]

{{0, 0, 7}, {0, 0, 10, 0}, {0, 3, 6, 1, 4}, {0, 6, 2}, {5, 0, 2, 3}, {5, 1, 2}}

If you wish to treat the numbers as strings in your sorting, you can modify it like so:

lessAsString[a_, b_] := Order @@ (ToString /@ {a, b}) === 1;

olexComp[_, {}] := False;
olexComp[{}, _] := True;
olexComp[{a_, as___}, {b_, bs___}] := lessAsString[a, b] || a === b && olexComp[{as}, {bs}];

Here is the example of such a sort:

In[5]:= Sort[{{0, 0, 7}, {5, 0, 2, 3}, {0, 0, 11, 0}, {0, 0, 1, 12}, {0, 6, 2}, {5, 1, 2}, {0, 3, 6, 1, 4}}, olexComp]

Out[5]= {{0, 0, 1, 12}, {0, 0, 11, 0}, {0, 0, 7}, {0, 3, 6, 1, 4}, {0, 6, 2}, {5, 0, 2, 3}, {5, 1, 2}}

Upvotes: 6

cah
cah

Reputation: 584

This should do it

{{0, 0, 7}, {5, 0, 2, 3}, {0, 0, 10, 0}, {0, 6, 2}, {5, 1, 2}, {0, 3, 
   6, 1, 4}} // SortBy[#, ToString] &

This works because lexically, comma and space precede the numbers, so {a,b} is lexically before {a,b,c}.

Upvotes: 1

Related Questions