more efficient code?

I have seen many times that people will rewrite the apple script code in more efficient “native” code instead.
It always runs much faster.

Is there a more efficient way of writing the following two lines of AS?


	set myWorkFolder to name of every folder of folder "g1:art department 2:work files2" whose name does not start with " "
	set myDataFolder to name of every file of folder "Datafile:DigitalPress" whose name starts with "2"


the second command took such a long time I got a timeout error. There are something like 4000 files in that DigitalPress directory.

thanks
david

You may use :

(*
 Based upon  http://macscripter.net/viewtopic.php?id=44806&p=2
 *)

use AppleScript version "2.5"
use framework "Foundation"
use scripting additions

on getFilesInFolder:aliasOrFile whichFormat:theFormat
	set regularFileKey to current application's NSURLIsRegularFileKey
	set aliasFileKey to current application's NSURLIsAliasFileKey
	set packageKey to current application's NSURLIsPackageKey
	set aliasResolutionOptions to current application's NSNumber's numberWithInteger:(512 + 256)
	
	set fileManager to current application's NSFileManager's defaultManager()
	set theNSURLs to (fileManager's contentsOfDirectoryAtURL:aliasOrFile includingPropertiesForKeys:{regularFileKey, aliasFileKey, packageKey} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value))
	set theNSURLs to theNSURLs's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:theFormat)
	
	-- Initialise an AS list to store the aliases. The script object's not necessary if you're not expecting many hits.
	script o
		property nameList : {}
	end script
	
	repeat with anNSURL in theNSURLs
		-- If this URL points to an alias file, get the original's URL instead. The process resolves symbolic links too for some reason ” including broken ones!
		set anNSURL to (current application's |NSURL|'s URLByResolvingAliasFileAtURL:anNSURL options:aliasResolutionOptions |error|:(missing value))
		if (anNSURL is missing value) then
			-- Alias file's original item not found.
		else
			-- Test filehood and packagehood (!).
			set fileOrPackageResults to (anNSURL's resourceValuesForKeys:{regularFileKey, packageKey} |error|:(missing value))
			-- If no problem and one of the results is true, store the URL as an alias.
			if ((fileOrPackageResults is not missing value) and (fileOrPackageResults's containsObject:true)) then set end of o's nameList to (anNSURL's lastPathComponent) as text
		end if
	end repeat
	
	return o's nameList
end getFilesInFolder:whichFormat:

#=====

on getFoldersInFolder:aliasOrFile whichFormat:theFormat
	set directoryKey to current application's NSURLIsDirectoryKey
	set aliasFileKey to current application's NSURLIsAliasFileKey
	set packageKey to current application's NSURLIsPackageKey
	set aliasResolutionOptions to current application's NSNumber's numberWithInteger:(512 + 256)
	
	set fileManager to current application's NSFileManager's defaultManager()
	set theNSURLs to (fileManager's contentsOfDirectoryAtURL:aliasOrFile includingPropertiesForKeys:{directoryKey, aliasFileKey, packageKey} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value))
	set theNSURLs to theNSURLs's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:theFormat)
	
	-- Initialise an AS list to store the aliases. The script object's not necessary if you're not expecting many hits.
	script o
		property nameList : {}
	end script
	
	repeat with anNSURL in theNSURLs
		-- If this URL points to an alias file, get the original's URL instead. The process resolves symbolic links too for some reason ” including broken ones!
		set anNSURL to (current application's |NSURL|'s URLByResolvingAliasFileAtURL:anNSURL options:aliasResolutionOptions |error|:(missing value))
		if (anNSURL is missing value) then
			-- Alias file's original item not found.
		else
			-- Test filehood and packagehood (!).
			set {theResult, isDirectory} to (anNSURL's getResourceValue:(reference) forKey:directoryKey |error|:(missing value))
			if (isDirectory is not missing value) and (isDirectory as boolean) then
				log "it's a folder or a package"
				set {theResult, isPackage} to (anNSURL's getResourceValue:(reference) forKey:packageKey |error|:(missing value))
				if (isPackage as boolean) then
					log "it's a package"
				else
					log "it's a folder"
					set end of o's nameList to (anNSURL's lastPathComponent) as text
				end if
			end if
		end if
	end repeat
	
	return o's nameList
end getFoldersInFolder:whichFormat:

#=====

set f to choose folder

# Builds a list of folderNames which doesn't start with a space char
set myWorkFolder to its getFoldersInFolder:f whichFormat:("lastPathComponent MATCHES '[^ ].*'")
# Builds a list of fileNames starting with the digit 2
set myDataFolder to its getFilesInFolder:f whichFormat:("lastPathComponent MATCHES '[2].*'")

If you have questions, I hope that an other helper would respond because I will be off the net during 10 days.

Yvan KOENIG running El Capitan 10.11.5 in French (VALLAURIS, France) jeudi 23 juin 2016 21:50:32

Here’s a reworking which combines the two handlers above, taking “files”, “folders”, or “items” (or their singulars) as an additional parameter. It also dispenses with the resolving of alias files and tidies up some nomenclature confusion in the variable names and comments. One thing to note about the predicate parameter is that it’s case-sensitive with regard to string values. If you need case-insensitivity, put “[c]” after the operator:
[format]“lastPathComponent BEGINSWITH[c] ‘F’”[/format]

(*
 Based upon  http://macscripter.net/viewtopic.php?id=44806&p=2
 *)

use AppleScript version "2.5"
use framework "Foundation"
use scripting additions

on getNamesInFolder(aliasOrFile, itemType, theFormat)
	set regularFileKey to current application's NSURLIsRegularFileKey
	set packageKey to current application's NSURLIsPackageKey
	
	-- Get NSURLs for all the visible items in the folder.
	set fileManager to current application's class "NSFileManager"'s defaultManager()
	set theNSURLs to (fileManager's contentsOfDirectoryAtURL:(aliasOrFile) includingPropertiesForKeys:({regularFileKey, packageKey}) options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value))
	set theNSURLs to theNSURLs's filteredArrayUsingPredicate:(current application's class "NSPredicate"'s predicateWithFormat:theFormat)
	
	-- Return all the items' names if we're simply looking for "items".
	if (itemType begins with "item") then return (theNSURLs's valueForKey:("lastPathComponent")) as list
	
	-- Otherwise we need to differentiate between folders and files. Initialise an AS list to store the names. 
	script o
		property nameList : {}
	end script
	
	set lookingForFiles to (itemType begins with "file") -- true if files wanted, false if folders.
	repeat with anNSURL in theNSURLs
		-- Test filehood and packagehood (!).
		set fileOrPackageResults to (anNSURL's resourceValuesForKeys:({regularFileKey, packageKey}) |error|:(missing value))
		-- If no problem and either (we're looking for files and this item's either a file or a package) or (we're not looking for files and this item's neither a file nor package) then store this item's name.
		if ((fileOrPackageResults is not missing value) and ((lookingForFiles) = ((fileOrPackageResults's containsObject:(true)) as boolean))) then set end of o's nameList to (anNSURL's lastPathComponent) as text
	end repeat
	
	return o's nameList
end getNamesInFolder

#=====

set f to choose folder

# Builds a list of folderNames which doesn't start with a space char
set folderNames to getNamesInFolder(f, "folders", "NOT(lastPathComponent BEGINSWITH ' ')")
# Builds a list of fileNames starting with the digit 2
set fileNames to getNamesInFolder(f, "files", "lastPathComponent BEGINSWITH '2'")

Another approach, perhaps easier to use if you’re unfamiliar with ASObjC predicate formats, would be this:

(* Parameters:
f: alias, bookmark, or Finder reference to a folder.
itemType: one of these strings: "files", "folders", or "items".
propertyKey: string representation of a property label, eg. "name", "name extension", "size".
comparisonOperator: string representation of a comparison operation, eg. "is", ">", "begins with".
comparisonValue: the value against which to compare the items (not a string representation thereof).
*)

on getNamesInFolder(f, itemType, propertyKey, comparisonOperator, comparisonValue)
	if (propertyKey is "name") then
		set FinderStuff to "tell app \"Finder\"
set o's allNames to name of " & itemType & " of f
set o's propertyValues to o's allNames
end"
	else
		set FinderStuff to "tell app \"Finder\" to set {o's allNames, o's propertyValues} to {name, " & propertyKey & "} of " & itemType & " of f"
	end if
	run script "on run {f, comparisonValue}
  script o
    prop allNames: missing value
    prop propertyValues: missing value
    prop nameList: {}
  end
  " & FinderStuff & "
  repeat with i from 1 to (count o's propertyValues)
    set thisValue to item i of o's propertyValues
    if (thisValue " & comparisonOperator & " comparisonValue) then set end of o's nameList to item i of o's allNames
  end
  return o's nameList
end" with parameters {f, comparisonValue}
end getNamesInFolder

-- Examples:
set f to (choose folder)
set folderNames to getNamesInFolder(f, "folders", "name", "does not begin with", " ")
set fileNames to getNamesInFolder(f, "files", "name", "begins with", "2")
set itemNames to getNamesInFolder(f, "items", "size", ">", 16384)