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.

Suppose I have a notebook with cells tagged with both numbers and words with numbers always list first, and some cells without cell tags e.g.:

Notebook[{
Cell[ ..., CellTags->{"1","cat"}],
Cell[ ..., CellTags->{"2","dog"}],
...
Cell[ ...],
Cell[ ..., CellTags->{"7","cow"}],
...
}, notebook options ...]

What is the easiest way to sort the cells based on 1) cell tag numbers, i.e. the first element in the cell tag list; and 2) cell tag words, i.e. the second element in the cell tag list?

Note that there could be additional tags but the first and second tags are always number and single word. Note also there there is unlikely to be grouped cells (none at this stage), although a solution that took cell grouping into account and rendered a sorted ungrouped answer would be fine. I want a fast way to sort a notebook and render the newly sorted form. I'm thinking ideally I'd like a palette button for this.

share|improve this question
1  
I am generally useless at this kind of programmatic Notebook manipulation. I appreciate questions like this because I learn a lot from the answers. –  Mr.Wizard Feb 23 '12 at 12:44
    
I might have another look at my answer today. I'm thinking that Cases is quite repetitive. Maybe just use it once on the content and then use Ordering would be more efficient. –  Mike Honeychurch Feb 23 '12 at 20:51
add comment

1 Answer 1

This is actually something I am working on for real at the moment. This is what i have got so far:

nb = NotebookOpen["path/to/notebook.nb"];
SelectionMove[nb, All, Notebook];
content = NotebookRead[nb];
NotebookDelete[nb];

For searching based on the number listed as the first tag:

sorted = SortBy[content, 
 Cases[#, HoldPattern[
     Rule[CellTags, {x_ /; StringMatchQ[x, NumberString], __}]] :> 
    ToExpression@x] &]

and for searching based on the word in the second tag:

sorted = SortBy[content, 
 Cases[#, HoldPattern[Rule[CellTags, {_, x_, __}]] :> x] &]

With both of these methods the untagged cells are returned first ...which is ok. Then

Scan[NotebookWrite[nb, #] &, sorted];
NotebookSave[nb];
NotebookClose[nb];

This is a little bit slow but seems to be doing the job.

Edit

So this code seems to be doing the job on the notebooks i needed to use this with. Would still be interested in suggestions from others.

ClearAll[sortNotebook];

Options[sortNotebook] = {"sortby" -> "Number"};

sortNotebook[file_String, OptionsPattern[]] := 
 Module[{nb, opt = OptionValue["sortby"], sorted},

  nb = NotebookOpen[file];
  SelectionMove[nb, All, Notebook];
  content = NotebookRead[nb];
  NotebookDelete[nb];
  Which[
   opt === "Number", 
   sorted = 
    SortBy[content, 
     Cases[#, 
       HoldPattern[
         Rule[CellTags, {x_ /; StringMatchQ[x, NumberString], __}]] :>
         ToExpression@x] &],
   opt === "Task", 
   sorted = 
    SortBy[content, 
     Cases[#, HoldPattern[Rule[CellTags, {_, x_, __}]] :> x] &],
   opt =!= "Number" && opt =!= "Task", 
   Print["you messed up with the option names"]
   ];
  Scan[NotebookWrite[nb, #] &, sorted];
  NotebookSave[nb];
  NotebookClose[nb];
  ]
share|improve this answer
add comment

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.