How can I order a list of strings in Mathematica lexicographically?

Whatever I try, nothing works.

Sort[Union[{"(+3k-1,-4n/3-3m+k-7/3)", "(+3k+1,-n-m+k)", "(+3k-1,-n-m+k-1)"}], OrderedQ[{#1, #2}] &]

gives

{"(+3k-1,-4n/3-3m+k-7/3)", "(+3k+1,-n-m+k)", "(+3k-1,-n-m+k-1)"}

which makes no sense to me. "(+3k+"something should not be between two "(+3k-"somethings unless the length comes first to decide the ordering. But then the shortest one shouldn’t be in the middle. I can’t believe that there is no built in way in Mathematica to do this right.

This took digging.

In the reference page for Sort (http://reference.wolfram.com/language/ref/Sort.html), under Details,

Sort orders strings as in a dictionary, with uppercase versions of
letters coming after lowercase ones. Sort places ordinary letters
first, followed in order by script, Gothic, double-struck, Greek, and
Hebrew. Mathematical operators appear in order of decreasing
precedence.

+ and - have the same precedence. (http://reference.wolfram.com/language/tutorial/OperatorInputForms.html, half-way down.)

To get these in ASCII order, you will have to write your own function.

The precedence being the same doesn’t quite explain the result, because + and - do get sorted (based on their long names, I believe, though that is undocumented).

In[2]:= Sort[{"+", "-"}]

Out[2]= {"-", "+"}

To get these in ASCII order, you will have to write your own function.

In[18]:= Clear[WRule]
WRule = {"-" -> "WMinus", "+" -> "WPlus"};
StringReplace[
   Sort[StringReplace[{"(+3k-1,-4n/3-3m+k-7/3)", "(+3k+1,-n-m+k)", "(+3k-1,-n-m+k-1)"}, WRule], OrderedQ[{#1, #2}] &], 
   Reverse /@ WRule]

Out[20]= {"(+3k-1,-4n/3-3m+k-7/3)", "(+3k-1,-n-m+k-1)", "(+3k+1,-n-m+k)"}

or if the minus should appear later

In[21]:= Clear[WRule]
WRule = {"-" -> "WLast", "+" -> "WFirst"};
StringReplace[
 Sort[StringReplace[{"(+3k-1,-4n/3-3m+k-7/3)", "(+3k+1,-n-m+k)", "(+3k-1,-n-m+k-1)"}, WRule], OrderedQ[{#1, #2}] &], 
 Reverse /@ WRule]

Out[23]= {"(+3k+1,-n-m+k)", "(+3k-1,-4n/3-3m+k-7/3)", "(+3k-1,-n-m+k-1)"}

I can’t believe that there is no built in way in Mathematica to do
this right.

It’s possible to convert forth and back to character code, but then there is the problem, that the order of lists is undefined

In[32]:= {40, 43, 51, 107, 45, 49, 44, 45, 52, 110, 47, 51, 45, 51, 
  109, 43, 107, 45, 55, 47, 51, 41} > {40, 43, 51, 107, 43, 49, 44, 
  45, 110, 45, 109, 43, 107, 41}

Out[32]= {40, 43, 51, 107, 45, 49, 44, 45, 52, 110, 47, 51, 45, 51, 
  109, 43, 107, 45, 55, 47, 51, 41} > {40, 43, 51, 107, 43, 49, 44, 
  45, 110, 45, 109, 43, 107, 41}

so let’s do something simple minded

In[36]:= Clear[weitzerOrder]
weitzerOrder[l1_List?VectorQ, l2_List?VectorQ] := 
 Block[{o = 1, len1 = Length[l1], len2 = Length[l2]}, 
  While[l1[[o]] == l2[[o]] && o <= Min[len1, len2], o++];
  If[l1[[o]] < l2[[o]],
   True, (* else *)
   If[o > len1,
    True, (* else *)
    False
    ]
   ]
  ]
FromCharacterCode /@ 
 Sort[ToCharacterCode /@ {"(+3k-1,-4n/3-3m+k-7/3)", "(+3k+1,-n-m+k)", "(+3k-1,-n-m+k-1)"}, weitzerOrder[#1, #2] &]

Out[38]= {"(+3k+1,-n-m+k)", "(+3k-1,-4n/3-3m+k-7/3)", "(+3k-1,-n-m+k-1)"}

But the test fails despite Sort works (anti-konform to the character code)

In[1]:= "+" < "-"
Out[1]= "+" < "-"
    
In[2]:= {"+"} < {"-"}
Out[2]= {"+"} < {"-"}
    
In[8]:= ToCharacterCode["+"] < ToCharacterCode["-"]
Out[8]= {43} < {45}

In[12]:= weitzerOrder[ToCharacterCode["+"], ToCharacterCode["-"]]
Out[12]= True