Filter contacts by zip code

Hi!
I managed to build a script to filter contacts by zip code.
Unfortuantely it is very slow. Does anyone know how to make this faster by using ASOC?

Here is my script:


tell application "Contacts"
	set _ids to every person whose zip of first address starts with "82"
	set _names to {}
	repeat with _id in _ids
		set _name to name of _id
		set the end of _names to _name
	end repeat
	return _names
end tell

Hi.

Something like this?

use AppleScript version "2.5" -- Mac OS 10.11 (El Capitan) or later.
use framework "Foundation"
use framework "Contacts"

on join(listOfText, delimiter)
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to delimiter
	set txt to listOfText as text
	set AppleScript's text item delimiters to astid
	return txt
end join

on run argument
	-- set argument to {"82"}
	if (argument's class is list) then set argument to beginning of argument
	set |⌘| to current application
	set contactStore to |⌘|'s class "CNContactStore"'s new()
	-- Request one copy of every contact of every container (although there's probably only one container)
	-- along with their names, addresses, and IDs and build a single mutable array of all the results.
	set allContainers to contactStore's containersMatchingPredicate:(missing value) |error|:(missing value)
	set contactArray to |⌘|'s class "NSMutableArray"'s new()
	set keysNeeded to |⌘|'s class "NSArray"'s arrayWithArray:({|⌘|'s CNContactGivenNameKey, |⌘|'s CNContactFamilyNameKey, |⌘|'s CNContactOrganizationNameKey, |⌘|'s CNContactTypeKey, |⌘|'s CNContactPostalAddressesKey, |⌘|'s CNContactIdentifierKey})
	repeat with thisContainer in allContainers
		set contactPredicate to (|⌘|'s class "CNContact"'s predicateForContactsInContainerWithIdentifier:(thisContainer's identifier()))
		set theseContacts to (contactStore's unifiedContactsMatchingPredicate:(contactPredicate) keysToFetch:(keysNeeded) |error|:(missing value))
		tell contactArray to addObjectsFromArray:(theseContacts)
	end repeat
	
	-- Filter the array for contacts having any address with a post (zip) code beginning with the given argument.
	set zipFilter to |⌘|'s class "NSPredicate"'s predicateWithFormat_("ANY postalAddresses.value.postalCode BEGINSWITH %@", argument)
	tell contactArray to filterUsingPredicate:(result)
	
	-- Get the previously requested info re the survivors' given names, family names,
	-- and/or organisation names, and IDs, coercing the results to AppleScript lists of text.
	set givenNames to (contactArray's valueForKey:("givenName")) as list
	set familyNames to (contactArray's valueForKey:("familyName")) as list
	set organisationNames to (contactArray's valueForKey:("organizationName")) as list
	set contactTypes to (contactArray's valueForKey:("contactType")) as list
	set IDs to (contactArray's valueForKey:("identifier")) as list
	
	-- Collate the results, constructing the names according to contact type.
	set _results to {}
	repeat with i from 1 to (count contactTypes)
		if (item i of contactTypes is 0) then -- Person.
			set _name to (item i of givenNames) & space & (item i of familyNames)
		else -- item i of contactTypes is 1 (organisation)..
			set _name to (item i of organisationNames)
		end if
		set end of _results to "{'title':" & quoted form of _name & ",'icon':'personTemplate.png','url':'addressbook://" & item i of IDs & "'}"
	end repeat
	
	-- Coerce the results list to a single text.
	-- It's best practice always to set Applescript's text item delimiters explicitly for this.
	return join(_results, ",")
end run

Edit: Modified in the light of the reply immediately below.

Thank you! This performs sooo much better.

I developed my script a bit further in the meantime for use within my LaunchBar action. I mainly added the entry ID. This way I can directly open a given result in Contacts (with some cleanup in the javascript part of my LaunchBar action)
I just don’t know how to integrate the ID part in your version. I guess I need to learn ASOC eventually.

Again, thank you!


on run (argument) -- e.g. "82"
        -- set argument to "82
	tell application "Contacts"
		set _persons to every person whose zip of first address starts with argument
	end tell

	set _results to {}
	repeat with _person in _persons
		set _name to name of _person
		set _id to id of _person as string
		set _result to "{'title':'" & _name & "','icon': 'personTemplate.png', 'url':'addressbook://" & _id & "'},"
		set the end of _results to _result
	end repeat

	set output to _results as string
	return output
end run

Here is a shortened version of the first script in post #1


tell application "Contacts"
	set _names to name of every person whose zip of first address starts with "82"
end tell
return _names

I’ve modified the script to behave more like your script in post #3.

Awesome! Thank you so much. It works great. Also thanks for the infos in the comments.