1
|
3818 Views
|
9 Replies
|
10 Total Likes
View groups...
Share
GROUPS:

# Help with multiple sort of lists

Posted 11 years ago
 I have an {n x 3} list and wish to sort first by column 3 and then by column 2 and still maintain the first sort when I do the second sort. For example I have this list.l = {{b, 98, 999}, {c, 75, 999}, {a, 100, 999}, {d, 67, 987}, {e, 98, 987}}and using this sort does not do what I need it to do.Sort[l,#1[[3]]>#2[[3]]&[[2]]>#2[[2]]&];Column[l]produces this output{b,98,999}{c,75,999}{a,100,999}{d,67,987}{e,98,987}I am trying to get this result{a,100,999}{b,98,999}{c,75,999}{e,98,987}{d,67,987}I have tried SortBy and cant get any closer, I have re-organised the rows so the numbers are first and still no success. Is this possible using the Sort command or will I have to resort to a more programmable way?
9 Replies
Sort By:
Posted 11 years ago
 Sorry about my late reply, and thank you Shenghui  and Sander for your replies.  The SortBy method suggested by Sander is an excellent method, I have now extended my sorts to 3 and 4 columns.  One thing worthy of note, I have found  sorting a text field does not respond to -#[[4]].  it sorts but alphabetically and can't reverse the sort.  I don't find this much of a problem though.  Thanks again for your help.Paul.
Posted 11 years ago
 -"string" does not make much sense, for numbers it does: it will maken 90 and 100 (increasing order) change to -90 and -100 (decreasing order)you have to make a special function to deal with reverse strings: you can change all charachters:a.b.c.d....z -> z.y.x.w.....aand use that to sort it. Then you can achieve reverse ordering with strings.
Posted 11 years ago
 This can be easily solved with SortBy, and using multiple functions to sort out 'ties'.l={{b,98,999},{c,75,999},{a,100,999},{d,67,987},{e,98,987}};SortBy[l,{-#[[3]]&,-#[[2]]&}];%//Gridout:a    100    999b    98    999c    75    999e    98    987d    67    987
Posted 11 years ago
 @Sander, this is very neat. @Paul, The documentation for this trick is here ( Details -> Item 3) . My code basically shows what it means.
Posted 11 years ago
 Thanks Shenghui Yang! This one saved me already many many times ;-)
Posted 11 years ago
 Hi Sander,Question: What do you think is reason the following fails: In[1]:= Clear[l] l = {{b, 98, 999}, {c, 75, 999}, {a, 100, 999}, {d, 67, 987}, {e, 98,      987}};  In[3]:= Clear[clearySort] clearySort[x_, y_] := If[x[[-1]] > y[[-1]], True,   If[x[[-2]] > y[[-2]], True, False]   ] In[5]:= SortBy[l, clearySort]Out[5]= {{a, 100, 999}, {b, 98, 999}, {c, 75, 999}, {d, 67, 987}, {e, 98, 987}}it's wrong in the last two elements and clearySort knows about that:In[6]:= clearySort[{d, 67, 987}, {e, 98, 987}]Out[6]= FalseWasn't it the meaning that sort stops only if all distinct pairs say "True" (or at least "Don't know") under the criterion?
Posted 11 years ago
 SortBy does not work on pairs, but on individual elements only:SortBy[f,expr] will evaluate:g=f[expr[[1]]], f[expr[[2]]], f[expr[[2]]].....  (or g=f/@exp for short)f is then return in the order given by Ordering.So in your example clearysort is never executed because clearlysort[x_] is not defined. It will be left unevaluated:g={clearysort[{b,98,999}], ... ,clearysort[{e,98,987}]}If we sort g it will just ignore the heads because they are all the same, and that is why you get a list back in the form of a..., b... , c...., d..., e....FYI: your code does work if you use Sort instead of SortBy.Hope this helps.
Posted 11 years ago
 You are rightIn[3]:= SortBy[l, True]Out[3]= {{a, 100, 999}, {b, 98, 999}, {c, 75, 999}, {d, 67, 987}, {e, 98, 987}}the possibility of simply being ignored had been ignored, thanks.
Posted 11 years ago
 @Paul, this is usually done by mixing the Sort function and the GatherBy function. The following code generates the result in the form that you have requested: When you try to do the secondary sort, you basically just want to operate on the subset of the data sharing the same third element. GatherBy gives you a nice and neat way to collect such subsets. Also in this code "%" denotes the result from the last step and "/@" means Map function. The copyable code is here: l = {{b, 98, 999}, {c, 75, 999}, {a, 100, 999}, {d, 67, 987}, {e, 98, 987}};Sort[l, #1[[3]] > #2[[3]] &];GatherBy[l, #[[3]] &];Sort[#, #1[[2]] > #2[[2]] &] & /@ %;TableForm[Flatten[%, 1]]