Hi. Welcome to MacScripter.
You don’t say what you mean by “crash”. (Spinning beachball? Error message? Smell of burning?) But one of the problems when sending a lot of commands to an application ” as when individually scripting every email of every person in Contacts ” is the sheer amount of event passing which takes place. For each command, the script broadcasts a command event; the application recognises the event as intended for it, carries out the command, and sends an acknowledgement when it’s done; the script then goes on to the next command.
On top of this, the application has no idea of the purpose or progress of the script. It just receives individual commands out of the blue ” say, to do something with the label of email x of person y. It then internally looks up person y, person y’s email x, and the email’s label property, and carries out the action. Once it’s done that and sent an acknowledgement, it’s finished. If the very next command is for the very same property of the same email of the same person, the internal look-up happens all over again. (There are probably technical inaccuracies in this description. I’m just giving a way of thinking about it which pays off when scripting.)
There’s not much you can do about this in your script when it comes to setting the email property values, but you can get the original values in bulk. This requires only one command (possibly two events) and the application moves internally between the emails instead of starting again every time. So your sorting loop for each person could be:
-- Sort emails into lists based on labels
-- First get the values of all this person's email labels and values in one go.
set {email_labels, email_values} to {label, value} of emails
-- Then do the sorting without talking to the application.
repeat with i from 1 to (count email_labels)
set theLabel to item i of email_labels
if theLabel is "work" then
set work_labels to work_labels & "work"
set work_values to work_values & item i of email_values
else if theLabel is "home" then
set home_labels to home_labels & "home"
set home_values to home_values & item i of email_values
else if theLabel is "other" then
set other_labels to other_labels & "other"
set other_values to other_values & item i of email_values
else
set unknown_labels to unknown_labels & theLabel
set unknown_values to unknown_values & item i of email_values
end if
end repeat
Even better would be to get the label and value values for every email of every person at once, although the vanilla parsing code would have to be slightly more complex.
This approach also goes a little way towards answering your third question. For instance, the repeat loop in the version of the code above can easily be adapted and put into its own handler. You pass the handler a list of label values and a list of value values and it returns eight sorted lists or, preferably, the two resulting from the concatentations of the two groups of four.
While on the subject of concatenation, when appending single items to lists, it’s more efficient to append the items to the existing lists than to create new lists by concatentation:
if theLabel is "work" then
set end of work_labels to "work"
set end of work_values to item i of email_values
else if theLabel is "home" then
set end of home_labels to "home"
set end of home_values to item i of email_values
-- etc.
I haven’t actually run this code, but it looks OK:
tell application "Contacts"
-- set thePeople to selection
set thePeople to people
repeat with aPerson in thePeople
tell aPerson
-- Get the values of all this person's email labels and values in one go.
set {email_labels, email_values} to {label, value} of emails
-- Sort labels and values into lists based on labels
set {all_labels, all_values} to my groupByLabel(email_labels, email_values) -- 'my' because the handler call's in a 'tell' statement.
repeat with i from 1 to (count all_labels)
set anEmail to email i
set label of anEmail to item i of all_labels
set value of anEmail to item i of all_values
end repeat
save
end tell
end repeat
end tell
on groupByLabel(label_list, value_list)
set work_labels to {}
set home_labels to {}
set other_labels to {}
set unknown_labels to {}
set home_values to {}
set work_values to {}
set other_values to {}
set unknown_values to {}
repeat with i from 1 to (count label_list)
set theLabel to item i of label_list
set theValue to item i of value_list
if theLabel is "work" then
set end of work_labels to "work"
set end of work_values to theValue
else if theLabel is "home" then
set end of home_labels to "home"
set end of home_values to theValue
else if theLabel is "other" then
set end of other_labels to "other"
set end of other_values to theValue
else
set end of unknown_labels to theLabel
set end of unknown_values to theValue
end if
end repeat
-- This part will place "work" emails first, then "home, ... etc.
set all_labels to work_labels & home_labels & other_labels & unknown_labels
set all_values to work_values & home_values & other_values & unknown_values
return {all_labels, all_values}
end groupByLabel