Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I have a list of sublists. One element of each sublist is a string element. For example:

list = {{1, "banana", 3}, {3, "orange", 1}, {2, "apple", 2}};

When I sort by the first element of each sublist, an integer, I receive the results that I was looking for.

In[]=  Sort[list, #1[[1]] < #2[[1]] &]
Out[]= {{1, "banana", 3}, {2, "apple", 2}, {3, "orange", 1}}

Same for when I sort by the third element of each sublist, an integer again.

In[]=  Sort[list, #1[[3]] < #2[[3]] &]
Out[]= {{3, "orange", 1}, {2, "apple", 2}, {1, "banana", 3}}

Now, when I sort by the second element of each sublist, a string, I see results that are unexpected.

In[]=  Sort[list, #1[[2]] < #2[[2]] &]
Out[]= {{1, "banana", 3}, {3, "orange", 1}, {2, "apple", 2}}
expected: {{2, "apple", 2}, {1, "banana", 3}, {3, "orange", 1}}

I tried with Order, same unexpected result.

In[]=  Sort[list, Order[#1[[2]], #2[[2]]] &]
Out[]= {{1, "banana", 3}, {3, "orange", 1}, {2, "apple", 2}}
share|improve this question

closed as off-topic by Kuba, m_goldberg, ciao, Michael E2, Yves Klett Mar 26 '14 at 9:26

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "This question arises due to a simple mistake such as a trivial syntax error, incorrect capitalization, spelling mistake, or other typographical error and is unlikely to help any future visitors, or else it is easily found in the documentation." – Kuba, m_goldberg, ciao, Michael E2, Yves Klett
If this question can be reworded to fit the rules in the help center, please edit the question.

MMA sorts Strings correctly, only not with Less or friends. You should've done your test with SortBy and then everything is ok: SortBy[list, #[[2]] &] –  Kuba Mar 25 '14 at 17:19
@Kuba Thanks! I feel like an idiot recreating the wheel. ;) –  mmorris Mar 25 '14 at 17:30
I wouldn't use such strong words. Many of us have done similar things ;) –  Kuba Mar 25 '14 at 17:31
@Kuba please post as an answer. –  mmorris Mar 25 '14 at 17:34
I do not feel competent enough to elaborate string sorting topic, so unless someone will kindly do this it will probably be closed as simple mistake. Don't worry :) –  Kuba Mar 25 '14 at 17:36

1 Answer 1

So I simplified the problem, I created a list of fruit. Sorting the fruit list without the ordering function that produces the expected result.

In[]=   Sort[list[[All, 2]]]
Out[]= {"apple", "banana", "orange"}

However when I sort the fruit list with an ordering function, I see the same unexpected results.

In[]=  Sort[list[[All, 2]], #1 < #2 &]
       Sort[list[[All, 2]], Order &]
       Sort[list[[All, 2]], Order[#1, #2] &]
Out[]= {"banana", "orange", "apple"}
Out[]= {"banana", "orange", "apple"}
Out[]= {"banana", "orange", "apple"}

Okay, the ordering function seems to be the cause of my confusion. Looking inside the ordering function.

MyCompareOrder[a_, b_] :=
 (Print["a:" <> ToString[a] <> 
        "  b:" <> ToString[b] <> 
        "  Order:" <>ToString[Order[a, b]]];
  Order[a, b])
Sort[list[[All, 2]], MyCompareOrder]

a:banana  b:orange  Order:1
a:orange  b:apple  Order:-1
{"banana", "orange", "apple"}

Hmmmm shouldn't there have been 3 calls to MyCompareOrder, only two print? Lets try that on something we know works, a list of the first elements of the sublist.

MyCompareLessThan[a_, b_] :=
 (Print["a:" <> ToString[a] <> 
        "  b:" <> ToString[b] <> 
        "  <:" <> ToString[a < b]];
  a < b)
Sort[list[[All, 1]] , MyCompareLessThan]

a:1  b:3  <:True
a:3  b:2  <:False
a:1  b:2  <:True
{1, 2, 3}

Great, three comparisons, I am not crazy. Lets try MyCompareOrder on the list of the first elements of the sublist.

Sort[list[[All, 1]] , MyCompareOrder]
a:1  b:3  Order:1
a:3  b:2  Order:-1
{1, 3, 2}

Hmmm only two comparisons. It must me the the ordering function. And there it hit me. The ordering function is looking for True or False, not -1, 0, or 1. I fixed MyCompareOrder by adding 1 == in front of Order[a, b].

MyCompareOrderFixed[a_, b_] :=
       "a:" <> ToString[a] <> 
       "  b:" <> ToString[b] <> 
       "  Order:" <> ToString[1 ==Order[a, b]]];
      1 == Order[a, b])
Sort[list[[All, 2]], MyCompareOrderFixed]

a:banana  b:orange  Order:True
a:orange  b:apple  Order:False
a:orange  b:apple  Order:False
{"apple", "banana", "orange"}

Sort[list[[All, 1]], MyCompareOrderFixed]
a:1  b:3  Order:True
a:3  b:2  Order:False
a:1  b:2  Order:True
{1, 2, 3}

Great everything works. Applying the knowledge gained to the original question.

In[]=  Sort[list, 1 == Order[#1[[2]], #2[[2]]] &]
Out[]= {{2, "apple", 2}, {1, "banana", 3}, {3, "orange", 1}}

Finally, what I was expecting to see.

While plodding through this, I also found out "apple" < "orange" does not evaluate to True it evaluates to "apple" < "orange". I supposed that this is why Sort[list, #1[[2]] < #2[[2]] &] fails. As for Sort working on a list of Strings it must not use < for the ordering function for a list of strings.

There is a good chance that my explanation is off, please correct any mistakes.

So I answered my question, but is there a more straight forward way to sort a list of sublists containing string elements, sorting by the string elements?

share|improve this answer

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