Is there an easier / faster way to do this...

Appreciate everyone reading and taking the time to help out…

I am writing an AppleScript that matches a telephone number retrieved from the Messages application to the telephone numbers in Contacts in order to retrieve the name of the person who sent the message [as I could not figure out how to retrieve the name of the person directly from within Messages – is there a way?]

The problem with the script is that it takes a very long time to run and, because I am new to AppleScript, I would appreciate any and all assistance as to how:

  1. This task can be coded to run faster [i.e. retrieving the name of the person who sent the message from within Messages]; or

  2. This script can be coded to run faster [i.e. retrieving the name of the person who sent the message from within Contacts but faster].

The script is as follows:



tell application "Contacts"
	
	set peopleCount to (count every person) -- Determine the number of records to loop through
	
	set testPhoneNumber to "+1 (XXX) YYY-ZZZZ" -- Determine the telephone number to search for.  To be replaced by a handler.
	
	repeat with i from 1 to peopleCount
		set phoneNumber to get value of every phone of person i -- Get all telephone numbers of person i
		if phoneNumber contains testPhoneNumber then
			set peopleName to first name of person i & " " & last name of person i
			set i to peopleCount
		end if
	end repeat
	
	log peopleName
	
end tell


Thanks in advance for your assistance.

Could not test right off but a good thing to do when working on huge lists is to test item 1 and then set the list to rest of it (in this case, it would be the list of every persons) so that item 1 is deleted each time and the list becomes lighter and lighter. Are you with me?
This said, couldn’t tell you wether this trick would speed up your script.

Hi,

you can get the name of the sender this way


tell application "Messages"
	set latestChat to chat 1
	set members to participants of latestChat
	set senderName to name of item 1 of members
end tell

StefanK;

Appreciate the response…I will test this later today and report back…it would be great were this to solve my problem…stay tuned!

As long as you’re matching the entire phone number, not just part of it (e.g. to find a person in a given area code you’d still need to use some sort of a loop), then a single query should do it:

set phoneNumber to "01235556789" -- digits only
tell application "Contacts" to get name of first person where phoneNumber is in value of every phone

BTW, you might want to use every person rather than first person as it’s possible for folks to share a phone.

p.s. This is one of those lovely examples that totally reaffirms my faith in the whole AppleScript stack, wonky and wobbly as it may be. When it’s bad it’s lousy, but when it’s good it’s beautiful.

Hi.

Stefan’s reply is obviously the answer to your problem. But with regard to the script you posted, the two main speed tricks when scripting an application ” especially when you need to search through its elements for a particular match ” are:

  1. Limit the number of commands the script sends to the application (as I see has hhas now suggested).
  2. Limit the amount of thinking the application has to do in response to each command. (This is unlike hhas’s suggestion, which requires the application to make decisions based on the values it finds. How fast these decisions produce a result depends on how much data needs to be sifted and how efficiently filtering has been implemented in the application concerned.)

In the case of Contacts, you can get it to dump all the first names, last names, and phone numbers to the script in one go. (Or possibly it counts as three.) The result is three parallel lists. The script can then go through these lists itself without having to keep asking Contacts for each individual piece of information. Contacts in turn doesn’t have to keep finding each piece of information from a standing start and returning it to the script.

In a repeat beginning with repeat with i from 1 to peopleCount, setting the value of i to peopleCount doesn’t stop the repeat, because i is updated from a background counter, not simply incremented from its current value. The command to stop the repeat here would have to be exit repeat.



set testPhoneNumber to "+1 (XXX) YYY-ZZZZ" -- Determine the telephone number to search for.  To be replaced by a handler.

tell application "Contacts"
	set {firstNames, lastNames, phoneNumbers} to every person's {first name, last name, value of phones}
end tell

set peopleCount to (count firstNames) -- Determine the number of records to loop through
set peopleName to "" -- Dummy value in case the name isn't found below.

repeat with i from 1 to peopleCount
	if (item i of phoneNumbers contains testPhoneNumber) then
		set peopleName to item i of firstNames & " " & item i of lastNames
		exit repeat
	end if
end repeat

peopleName

@ StefanK:

Appreciate the assistance, help and patience…the code you provided worked great.

One follow up – as this seems to be my biggest stumbling block – is how do I use the Dictionary to determine the proper syntax as I tried for a very long to access the telephone numbers as you did [note: I was using the term buddy] but could never get it to work. Pointing me in the right direction on this would be very helpful…


@ hhas, appreciate your assistance as well…as far as your tip is concerned I would then have to somehow figure out who actually sent the message among the various people with the same phone number though this should not be much of an issue as I no of essentially no one who shares a cell phone or e-mail account which are the primary methods of sending iMessages and SMS


@ Nigael, appreciate your assistance as well…as far as your comment about set i to peopleCount not terminating the repeat loop would you be so kind to expand on this as I not not understand why not.


@All, one more item – in addition to how to reference / use the Dictionary as noted above – is that now that I have the names of who sent the Messages I noticed that the order that the messages appear in the Chat list is different from the order in which the messages appear in the Messages window. How can I get the script to process the chats in the same order in which they appear in the Messages window which is newest appears at the top and oldest appears at the bottom.

Thanks for the help.

It’s a potential issue regardless of how you implement your solution (designing reliable programs is all about nipping Murphy’s Law in the bug), but if you already know everyone has unique phone numbers then you don’t need to worry about it. At any rate I doubt you’ll find a faster, simpler way to lookup by phone number than the one-liner provided.

a dictionary can contain classes, elements, properties, commands, enumerations, types, records and event handlers.

the class chat is the parent class for text chat, audio chat and video chat.
chat has a property participants which is declared as a list of buddies.
Unlike an element whose items can be referenced by its class and name / index (e.g buddy “Joe”) a simple list contains only items referenced by index (e.g. item 1)

Stefan:

Again, thank you…I obviously need to – and most certainly will – do far more reading on the use of the Dictionary, classes, elements, etc. so that I can easily access / code the data and items that I need to reference.

One more thing – any idea about to solve the issue that the order that the messages appear in the Chat list is different from the order in which the messages appear in the Messages window. How can I get the script to process the chats in the same order in which they appear in the Messages window which is newest appears at the top and oldest appears at the bottom.

Thanks

In the repeat with kinds of repeat, the repeat mechanism only sets the variable, at the top of each iteration, in accordance with the stage reached in the repeat that’s been defined. The process doesn’t read the variable and isn’t affected by any interference with the variable’s value.


set l to {}

repeat with i from 1 to 10
	set i to 10 -- This doesn't affect the repeat's internal accounting.
	set end of l to i
end repeat

return l
--> {10, 10, 10, 10, 10, 10, 10, 10, 10, 10}

So the usual way to cut short this kind of repeat is with an explicit exit repeat. There are other ways of defining repeats which do take account of supplied values. For instance:


set l to {}

set i to 1
repeat until (i > 10)
	set end of l to i
	if (i is 3) then set i to 9
	set i to i + 1
end repeat

return l
--> {1, 2, 3, 10}

Got it, crystal clear…thank you…

the conversations seem to be unsorted in AppleScript.
You could sort them in code by the property updated which is an AppleScript date

Appreciate that…will have to look that one up…

Joel

A little out of place but I have spent over an hour searching the internet and can’t find a good resource that thoroughly explains the AppelScript Dictionary so please point me in the right directions…thx…

StefanK:

Appreciate the response and just getting back to you…the use of the updated property in conjunction with the use of a sorting script [see URL http://macscripter.net/viewtopic.php?id=43381 ] solved my problem, so much thanks.

Joel