So the question is how to get this kind of information:

enter image description here


enter image description here

This is one of my ideas:

get = Function[notebook,
  Block[{i = 0, cells},
       cells = Cells[notebook]; 
       # /. _Cell :> cells[[++i]]       (*a*)
       ] & @ Block[{Cell, cells, i = 0},

      Cell[CellGroupData[c_, ___], ___] := c;
      First @ NotebookGet[#]
      ] & @ notebook
   (*Ad a: We are using ReplaceAll instead of Cell[___]:=cells[[++i]] because 
we want to avoid counting inline cells. We also have to do this in separate Block so
Cell[CellGroupData will be flat already.*)

But NotebookGet is not so fast, the bigger the notebook the slower, obviously. For help notebook it takes about 2 seconds. Far to much in my opinion.

get[help] // AbsoluteTiming

enter image description here

On the other hand it is quite compact and deals well with InlineCells, nondefault CellGrouping or custom cell styles.

So is there faster alternative? It doesn't even have to deal with non standard cellgrouping etc.

  • $\begingroup$ Would the "internal cache information" at the end of the nb files be enough? $\endgroup$ – Silvia Feb 10 '15 at 3:00
  • $\begingroup$ @Silvia I will take a closer look later but it seems like a good idea. I was not aware of that, thanks. :) $\endgroup$ – Kuba Feb 10 '15 at 7:25
  • $\begingroup$ No problem :) I'm just not sure you want the CellObjects or just the outline structure. But any way there are CellIDs in the cache. $\endgroup$ – Silvia Feb 10 '15 at 7:45
  • $\begingroup$ @Silvia yes, probably I need them inside but if I can get the outline faster it is already something :) $\endgroup$ – Kuba Feb 10 '15 at 10:13

Since your code has a bottleneck in NotebookGet, the only way to speed it up directly would be to speed up the latter. If your notebook exists on disk, you may try using something like this:

nbget[nbfile_String?FileExistsQ] :=
   FirstCase[_Notebook]@ToHeldExpression@Import[nbfile, "String"];

nbget[nb_NotebookObject] :=
   With[{file = Quiet[NotebookFileName[nb], {NotebookFileName::nosv }]},
     nbget[file] /; file =!= $Failed

On my machine, it runs about 2-3 times faster than NotebookGet, and it seems to work correctly. Further speedup with your methods seems only possible if you write a custom parser that would be faster than ToExpression. This seems entirely possible, but certainly requires more work.


Thanks to Silvia`s suggestion I found even faster way:

<< AuthorTools`

NotebookFileOutline[EvaluationNotebook[]] ~ Do ~ {100} // AbsoluteTiming
{0.564001, Null} (*big notebook, done 100 times!*)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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