Thursday, August 02, 2007
Last shall be First versus NextItem
I have to search through some paragraphs in a story looking for the first one whose applied paragraph style name isn't in a particular list. This kind of search cannot be done using the features of find/change (in either CS2 or CS3) so I have to step through the paragraphs in order looking at each. This would seem to be what the nextItem() method was created for. But I've always been a bit nervous about its performance, so I thought I'd conduct a timing test. I clicked in a story with 83 paragraphs and ran this:
So, then I tried this approach which relies on the contained paragraph (i.e, paragraphs[0]) of the last insertionPoint of a paragraph being the next paragraph (hence: "last shall be first"):
Notice that I inserted a beep in the catch in this version. As I expected, the while loop exited in this case without the beep, so the try/catch was not actually necessary in this case.
Thinks: these timings were for CS2 on my G5. How about CS3? Because of plug-in issues, I couldn't run exactly the same document, so I picked a story in another that happened to have 141 paragraphs. The first script took 211 seconds on CS3 on my MacIntel iMac/20. The second script took just under 9 seconds. About 23 times faster.
The length of the story is a definite issue with the speed disadvantage of the nextItem approach. Inserting:
So, the "Last shall be First" technique is the one I shall continue to use.
var myStartTime = new Date();The first time I ran it, it gave me an error trying to get to the nextItem after quite a long time -- I realized that this might be happening at the end of the story (where there is no nextItem) so I added the try/catch and indeed, that was the problem. The script took: 28.575 seconds to run.
// Do something
var myStory = app.selection[0].parent;
var myPara = myStory.paragraphs[0];
var nextPara = myStory.paragraphs.nextItem(myPara);
try {
while (myPara != nextPara) {
myPara = nextPara;
nextPara = myStory.paragraphs.nextItem(myPara);
}
} catch(e) {}
var myEndTime = new Date();
var myDuration = (myEndTime - myStartTime)/1000; // Times are in milliseconds
alert(myDuration)
So, then I tried this approach which relies on the contained paragraph (i.e, paragraphs[0]) of the last insertionPoint of a paragraph being the next paragraph (hence: "last shall be first"):
var myStartTime = new Date();And this took: 3.848 seconds. Over seven times faster. No contest!
// Do something
var myStory = app.selection[0].parent;
var myPara = myStory.paragraphs[0];
var nextPara = myPara.insertionPoints[-1].paragraphs[0];
try {
while (myPara != nextPara) {
myPara = nextPara;
nextPara = myPara.insertionPoints[-1].paragraphs[0];
}
} catch(e) {beep()}
var myEndTime = new Date();
var myDuration = (myEndTime - myStartTime)/1000; // Times are in milliseconds
alert(myDuration)
Notice that I inserted a beep in the catch in this version. As I expected, the while loop exited in this case without the beep, so the try/catch was not actually necessary in this case.
Thinks: these timings were for CS2 on my G5. How about CS3? Because of plug-in issues, I couldn't run exactly the same document, so I picked a story in another that happened to have 141 paragraphs. The first script took 211 seconds on CS3 on my MacIntel iMac/20. The second script took just under 9 seconds. About 23 times faster.
The length of the story is a definite issue with the speed disadvantage of the nextItem approach. Inserting:
$.writeln(nextPara.index);into the loop allows you to watch progress in ESTK 2's Console and you can see that the further into the story the script gets the slower it gets.
So, the "Last shall be First" technique is the one I shall continue to use.