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'm having a bit of trouble figuring out the right Sort syntax to use on a list of lists. Consider the following list:

list=
{
 {"B0T", "Ch72", "T0p36K", "Vdiv2047p92", "Vg75V"},
 {"B0T", "Ch70", "T0p28K", "Vdiv2047p92", "Vg65V"},
 {"B0T", "Ch70", "T0p28K", "Vdiv2047p92", "Vg60V"}, 
 {"B0T", "Ch72", "T0p36K", "Vdiv2047p92", "Vg70V"} 
}

I would like the resulting list to have the following:

  • Order first by anything looking like "T[0-9p]+K" (regex), and rearrange to have this value be first
  • Then order by "Vg[0-9p]+V", and rearrange to have it be 2nd.
  • Then order by "Ch[0-9]+", and rearrange to 3rd,
  • Then order the rest in alphabetical order, and rearrange

So, the final outcome would be:

{
 {"T0p28K", "Vg60V", "Ch70", "B0T", "Vdiv2047p92"}, 
 {"T0p28K", "Vg65V", "Ch70", "B0T", "Vdiv2047p92"},
 {"T0p36K", "Vg70V", "Ch72", "B0T", "Vdiv2047p92"}, 
 {"T0p36K", "Vg75V", "Ch72", "B0T", "Vdiv2047p92"}
}

Note: while it looks like all of the columns would be the same at the beginning, they might not always have the same position, and the number of columns themselves might change.

FWIW, eventually I will be separating the strings above with:

valRegExp = 
 RegularExpression[
  "(Vdiv|T|Vbias|Vg|B|Ch)([Ss][Ww]|[\-0-9p]+)(K|V|T)?"];
Map[Flatten[StringCases[#, 
 valRegExp :> {"$1", StringReplace["$2", "p" -> "."], 
   "($3)"}], {2}][[1]] &, list]

Is there a way to sort them "in place"? Is this better approached as a two step function: first sort, then rearrange?

EDIT Heike's answer along with a call to

Clear[SortByColumn]

SortByColumn::usage = 
"SortByColumn[List,Column,Direction]: Returns the list sorted by \
'Column' in either ascending (Direction= \"asc\") or descending \
(Direction = \"desc\") order. Default is in ascending order. For \
sorting more than one column, input Column as a list. For example, \
Column={1,2} will sort first on Column 1, then on Column 2.";

SortByColumn[list_List, col_, dir_String: "asc"] := 
 Which[dir == "desc", 
  Sort[list, ! OrderedQ[{#1[[col]], #2[[col]]}] &], dir == "asc", 
  Sort[list, OrderedQ[{#1[[col]], #2[[col]]}] &]]

Actually solves my problem, I think.

share|improve this question
    
What have you tried? –  rcollyer Mar 12 '12 at 15:51
    
@rcollyer sorry for not posting the attempts. I had been trying to build up from first rearrange, then move, and then going with a column sort. My implementation of the rearrange was UGLY, and not really working well. However, I liked my column sort function, so I posted that at least. –  tkott Mar 12 '12 at 17:09

1 Answer 1

up vote 2 down vote accepted

If all the entries in your array are strings, then one way to sort it is to do something like this:

order[str_String /; 
   StringMatchQ[str, "T" ~~ (DigitCharacter | "p") .. ~~ "K"]] := 1
order[str_String /; 
   StringMatchQ[str, "Vg" ~~ DigitCharacter .. ~~ "V"]] := 2
order[str_String /; StringMatchQ[str, "Ch" ~~ DigitCharacter ..]] := 3
order[a_] := a

#[[Ordering[order /@ #]]] & /@ list

This method uses the fact that numbers come before strings in an ordered list.

share|improve this answer
1  
Is the Ordering construct you used in any way different from SortBy? –  Szabolcs Mar 13 '12 at 5:04

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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