What is the fastest way to get notebook CellGroups / Cells structure?

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

from

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
]
we want to avoid counting inline cells. We also have to do this in separate Block so


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


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.

• Would the "internal cache information" at the end of the nb files be enough? – Silvia Feb 10 '15 at 3:00
• @Silvia I will take a closer look later but it seems like a good idea. I was not aware of that, thanks. :) – Kuba Feb 10 '15 at 7:25
• 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. – Silvia Feb 10 '15 at 7:45
• @Silvia yes, probably I need them inside but if I can get the outline faster it is already something :) – 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:

ClearAll[nbget];
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 Silvias suggestion I found even faster way:

<< AuthorTools

NotebookFileOutline[EvaluationNotebook[]] ~ Do ~ {100} // AbsoluteTiming

{0.564001, Null} (*big notebook, done 100 times!*)