问题
AppleScript documentation suggests the following code to efficiently build a list:
set bigList to {}
set bigListRef to a reference to bigList
set numItems to 100000
set t to (time of (current date)) --Start timing operations
repeat with n from 1 to numItems
copy n to the end of bigListRef
end
set total to (time of (current date)) - t --End timing
Note the use of an explicit reference. This works fine at the top level of a script or within an explicit run handler, but if you run the same exact code verbatim within another handler like so:
on buildList()
set bigList to {}
set bigListRef to a reference to bigList
set numItems to 100000
set t to (time of (current date)) --Start timing operations
repeat with n from 1 to numItems
copy n to the end of bigListRef
end
set total to (time of (current date)) - t --End timing
end buildList
buildList()
it breaks, yielding an error message saying, "Can't make bigList into type reference." Why does this break, and what is the correct way to efficiently build a list within a handler other than run()?
回答1:
set end of l to i
seems to be faster than copy i to end of l
:
on f()
set l to {}
repeat with i from 1 to 100000
set end of l to i
end repeat
l
end f
set t to time of (current date)
set l to f()
(time of (current date)) - t
You could also use a script object:
on f()
script s
property l : {}
end script
repeat with i from 1 to 100000
copy i to end of l of s
end repeat
l of s
end f
set t to time of (current date)
set l to f()
(time of (current date)) - t
100000 is also over the limit of items that can be saved in compiled scripts, so you'll get an error like this if you run the script and try to save it as scpt:
The document “Untitled” could not be saved as “Untitled.scpt”.
You can either put set l to f()
inside a handler so l is local, add set l to {}
to the end, or save the script as .applescript.
回答2:
Here are the results and methods of a speed test I did a while ago. Note that the first result in each trial is slower because the script had not compiled previously.
list_speed.xlsx
回答3:
Adding "global bigList" to the first line of buildList() fixes the compiler error. It seems that within the run handler, variables are naked by default, and the "a reference to" operator is useful. However, in other contexts, variables are already essentially indirect references, and creating another reference layer breaks stuff. Declaring a global variable in these contexts strips the indirect reference and allows the "a reference to" operator to work, but this is unnecessary. Just use the default indirect reference.
If this is unclear, it's because I don't completely understand the mechanism. If you have a better grasp of what's going on here, please comment below.
来源:https://stackoverflow.com/questions/15753161/how-do-you-efficiently-build-a-list-within-a-handler-in-applescript