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, rasher, Michael E2, Yves Klett Mar 26 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, rasher, Michael E2, Yves Klett
If this question can be reworded to fit the rules in the help center, please edit the question.

3  
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 at 17:19
    
@Kuba Thanks! I feel like an idiot recreating the wheel. ;) –  mmorris Mar 25 at 17:30
    
I wouldn't use such strong words. Many of us have done similar things ;) –  Kuba Mar 25 at 17:31
    
@Kuba please post as an answer. –  mmorris Mar 25 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 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_] :=
     (Print[
       "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.