I ran my own timing tests this morning, timing just the filter code in each script. The initial URL fetch is common to all the scripts and takes up the bulk of their running time, so any vagaries while it’s in progress to need to be eliminated from the filter method comparison results.
Actual timings, as always, depend on the model and age of the computer, the system it’s running, how much processor time is diverted to background tasks during the tests, the user’s set-up, etc. In the current case, the number and distribution of files and folders in the user’s home directory could be factors. But although my home folder clearly contains far more stuff than peavine’s (junk accumulated over 27 years of Mac ownership), my results are broadly in line with his in regard to what’s faster than what. Only the original three folders were “skipped” in my tests. The scripts were run with all of them open at the same time in both Script Editor and Script Debugger and with a Numbers document open to note the results. I include the results below in case anyone’s interested — and because I wanted to experiment with peavine’s table posting technique. The most interesting results, as I mentioned somewhere above, are actually the different numbers of items reportedly returned depending on whether the scripts are run in Script Editor or Script Debugger! I’ll have to look into this later on.
@Nigel_Garvey
Can you tell us what’s your configuration?
The timing results you shared seem very fast to me.
With my MacPro 2013 under Monterey, your second script takes 28 seconds for 383696 total files and 375463 filtered.
Can you run this script and add it to your timing report?
use framework "Foundation"
use scripting additions
tell application "Finder" to set toKeep to (folders of (path to current user folder) whose name is not in {"Movies", "Music", "Pictures", "Library"}) as alias list
set filteredArray to current application's NSMutableArray's new()
set fileManager to current application's NSFileManager's defaultManager()
repeat with aKept in toKeep
set entireContent to (fileManager's enumeratorAtURL:aKept includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects()
set filteredArray to (filteredArray's arrayByAddingObjectsFromArray:entireContent)
end repeat
filteredArray's |count|()
Hi @ionah. I did the tests on my desktop machine, which is an iMac 18,3 with a 3.4 GHz Quad-Core Intel Core I5 processor running macOS Ventura 13.6.7. I didn’t bother copying the files over to my M3 MacBook to test there. Its screen’s tiny.
As I explained above, the comparative timings are only for the scripts’ filter set-up-and-execution parts, which will obviously be less than when the fetching of the disk data and creation of the original URL array are included.
On my iMac, your script takes 0.96 seconds in Script Editor and 1.047 seconds in Script Debugger, reporting 57190 items in both cases. Only getting the folder contents you actually want is clearly more efficient than getting your entire home folder contents and filtering out what you don’t. But in the spirit of peavine’s original enquiry and of not assuming that the “skipped” folders will be siblings in the same root folder, I didn’t pursue that path myself.
My original script got the entire contents of my home folder and skipped three folders (and their contents). In that context, I would not expect your above statement to be the case. In retesting and for testing purposes only, I skipped all but a few folders, and in that context I would expect your above statement to be the case. Do I misunderstand what you are saying?
Hi @peavine. I’m not quite clear myself what you’re asking. But what I was thinking is that your script and those derived from it don’t skip folders, they get the entire contents of the root folder and then filter the unwanted folders and their contents from the result. ionah’s most recent script does skip folders, hence its speed. But it’s only good where the folders are immediate subfolders of the root.
If anyone whose not an expert is passing by, the script can accept a list of folders coming from any place. It needs a small adaptation:
use framework "Foundation"
use scripting additions
set toKeep to {"/Applications", "/Users/Shared"}
set filteredArray to current application's NSMutableArray's new()
set fileManager to current application's NSFileManager's defaultManager()
repeat with aKept in toKeep
set anURL to (current application's NSURL's fileURLWithPath:aKept)
set entireContent to (fileManager's enumeratorAtURL:anURL includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects()
set filteredArray to (filteredArray's arrayByAddingObjectsFromArray:entireContent)
end repeat
filteredArray's |count|()
Nigel. You were responding to Jonas’ script, which I hadn’t read when I posted, and I now understand your comment. Sorry about that. And, BTW, in actual testing my thought was wrong anyways.
On investigation, it turned out that Script Debugger had been given full disk access on my machines whereas Script Editor hadn’t. Granting it to the latter has resulted in the scripts returning the same, higher counts in both editors. Another of life’s great mysteries solved!
FWIW, I did a bit more research to determine the relative speeds of the following approaches:
Get the contents of a home folder and subtract what is not wanted.
Get the wanted folders and get their contents.
The following script takes the second approach and is faster by a few milliseconds. It should be noted that this script has a flaw in that it does not return files in the home folder.
use framework "Foundation"
use scripting additions
on main()
set theFolder to "/Users/Robert"
set skipFolders to {"/Users/Robert/Movies", "/Users/Robert/Music", "/Users/Robert/Pictures"}
set keepFolders to getKeepFolders(theFolder, skipFolders)
set folderContents to getFolderContents(keepFolders)
end main
on getKeepFolders(theFolder, skipFolders)
set fileManager to current application's NSFileManager's defaultManager()
set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
set directoryKey to current application's NSURLIsDirectoryKey
set packageKey to current application's NSURLIsPackageKey
set folderContents to fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:{} options:4 |error|:(missing value)
set theFolders to current application's NSMutableArray's new()
repeat with anItem in folderContents
set {theResult, aDirectory} to (anItem's getResourceValue:(reference) forKey:directoryKey |error|:(missing value))
if aDirectory as boolean is true then
set {theResult, aPackage} to (anItem's getResourceValue:(reference) forKey:packageKey |error|:(missing value))
if aPackage as boolean is false then (theFolders's addObject:anItem)
end if
end repeat
set skipURLs to current application's NSMutableArray's new()
repeat with aFolder in skipFolders
set aURL to (current application's |NSURL|'s fileURLWithPath:aFolder)
(skipURLs's addObject:aURL)
end repeat
theFolders's removeObjectsInArray:skipURLs
return theFolders
end getKeepFolders
on getFolderContents(theFolders)
set fileManager to current application's NSFileManager's defaultManager()
set folderContents to current application's NSMutableArray's new()
repeat with aFolder in theFolders
set aFolderContents to (fileManager's enumeratorAtURL:aFolder includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects()
(folderContents's addObjectsFromArray:aFolderContents)
end repeat
folderContents's addObjectsFromArray:theFolders
return folderContents
end getFolderContents
main()
BTW, I did not coerce folderContents to a list because I did not test it that way. To view the script result in Script Editor, folderContents should be coerced to a list.