How do you efficiently build a list within a handler in AppleScript?

和自甴很熟 提交于 2019-12-10 14:49:21

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!