List Manipulation Routines

Working with lists is one of the most common procedures performed in scripts. However, the current version of AppleScript does not support the use of every...whose clauses when targeting lists. For example, the following statement will not work:

set the name_list to {"Bob", "Sal", "Wanda", "Sue"}
set every item of the name_list where it is "Bob" to "Carl"
--> Can't set {"Bob", "Sal", "Wanda", "Sue"} whose it = "Bob" to "Carl".

The following sub-routines are designed to resolve these issues and make working with lists easier.


Determining if a List Contains a Specific Item

No special sub-routine is needed to determine if a list contains a specific item. The following syntax will return a value of either true or false to indicate the presence of an item in the list:

set this_list to {"Sal", "Sue", "Bob", "Carl", "Sue"}
this_list contains "Bill"
--> false

Click to open example in the Script Editor applicationUsing the contains operator to determine whether an item is in a list:
 

set this_list to {"Sal", "Sue", "Bob", "Carl", "Sue"}
if this_list does not contain "Wanda" then
 set the end of this_list to "Wanda"
end if
return this_list
--> returns: {"Sal", "Sue", "Bob", "Carl", "Sue", "Wanda"}


Offset of an Item in a List

The following sub-routine is used when it is necessary to determine an item's numeric position in a list.:

set this_list to {"Sal", "Sue", "Bob", "Carl"}
list_position("Carl", this_list)
--> 4

Here's the sub-routine called in the previous example:

Click to open example in the Script Editor applicationA sub-routine for getting the offset of an item in a list:
 

on list_position(this_item, this_list)
 repeat with i from 1 to the count of this_list
 if item i of this_list is this_item then return i
 end repeat
 return 0
end list_position

The above sub-routine can be used to cross-reference data between corresponding lists. In the example script below the variable name_list contains a list of names while the second variable, phone_list, contains phone numbers corresponding to the individuals in the first list. The script uses the previous sub-routine to determine the list position of the name chosen by the user and then locates the phone number occupying the same position in the second list:

Click to open example in the Script Editor applicationUsing the previous sub-routine to cross-reference corresponding lists:
 

set the name_list to {"Sal", "Sue", "Bob", "Carl"}
set the phone_list to {"5-5874", "5-2435", "5-9008", "5-1037"}
set the chosen_person to choose from list the name_list with prompt "Choose a person:"
if the chosen_person is false then return "user cancelled"
set the phone_number to ¬
 item (list_position((chosen_person as string), name_list)) of the phone_list
display dialog "The phone extension for " & chosen_person & ¬
 " is " & phone_number & "." buttons {"OK"} default button 1

The following sub-routine is a variation of the previous sub-routine that will return the offset of multiple occurrences of an item within a list:

Click to open example in the Script Editor applicationA sub-routine for returning a list of offsets of an item in a list:
 

on list_positions(this_list, this_item, list_all)
 set the offset_list to {}
 repeat with i from 1 to the count of this_list
 if item i of this_list is this_item then
 set the end of the offset_list to i
 if list_all is false then return item 1 of offset_list
 end if
 end repeat
 if list_all is false and offset_list is {} then return 0
 return the offset_list
end list_positions

By passing a boolean value of true or false as the third passed parameter, you can use the sub-routine to retrieve all of the offsets of an item in a list:

set this_list to {"Sal", "Sue", "Bob", "Carl", "Sue"}
list_positions(this_list, "Sue", true)
--> {2, 5}

Or to retrieve the offset of the first matching item:

set this_list to {"Sal", "Sue", "Bob", "Carl", "Sue"}
list_positions(this_list, "Sue", false)
--> 2


Counting Occurrences of an Item in a List

The following sub-routine can be used to count how many times an item is in a specified list:

set this_list to {"Sal", "Sue", "Bob", "Carl", "Sue"}
count_matches(this_list, "Sue")
--> 2

And here's the sub-routine:

Click to open example in the Script Editor applicationA sub-routine to count the instances of an item in a list:
 

on count_matches(this_list, this_item)
 set the match_counter to 0
 repeat with i from 1 to the count of this_list
 if item i of this_list is this_item then ¬
 set the match_counter to the match_counter + 1
 end repeat
 return the match_counter
end count_matches


Insert Item(s) Into List by Position

The following sub-routine can be used to insert an item into a list. The passed parameters include the list to edit, the item to add, and the desired list position for the added item. Note that the item position can be specified in relation to the end of the list by passing a negative number as the offset from the end of the list:

set this_list to {"Sal", "Sue", "Bob", "Carl"}
set this_list to insert_listitem(this_list, "Wanda", 3)
--> {"Sal", "Sue", "Wanda", "Bob", "Carl"}

set this_list to {"Sal", "Sue", "Bob", "Carl"}
set this_list to insert_listitem(this_list, {"Wanda", "Alberta"}, 3)
--> {"Sal", "Sue", "Wanda", "Alberta", "Bob", "Carl"}

set this_list to {"Sal", "Sue", "Bob", "Carl"}
set this_list to insert_listitem(this_list, {{"Wanda", "Alberta"}}, 3)
--> {"Sal", "Sue", {"Wanda", "Alberta"}, "Bob", "Carl"}

set this_list to {"Sal", "Sue", "Bob", "Carl"}
set this_list to insert_listitem(this_list, "Wanda", -1)
--> {"Sal", "Sue", "Bob", "Carl", "Wanda"}

set this_list to {"Sal", "Sue", "Bob", "Carl"}
set this_list to insert_listitem(this_list, "Wanda", -2)
--> {"Sal", "Sue", "Bob", "Wanda", "Carl"}

set this_list to {"Sal", "Sue", "Bob", "Carl"}
set this_list to insert_listitem(this_list, "Wanda", 5)
--> {"Sal", "Sue", "Bob", "Carl", "Wanda"}

Click to open example in the Script Editor applicationA sub-routine for inserting items into a list:
 

on insert_listitem(this_list, this_item, list_position)
 set the list_count to the count of this_list
 -- THE LIST POSITION INDICATES THE POSITION IN THE LIST
 -- YOU WANT THE ADDED ITEM TO OCCUPY
 if the list_position is 0 then
 return false
 else if the list_position is less than 0 then
 if (the list_position * -1) is greater than the list_count + 1 then ¬
 return false
 else
 if the list_position is greater than the list_count + 1 then return false
 end if
 if the list_position is less than 0 then
 if (the list_position * -1) is the list_count + 1 then
 set the beginning of this_list to this_item
 else
 set this_list to the reverse of this_list
 set the list_position to (list_position * -1)
 set this_list to (items 1 thru (list_position - 1) of this_list) & ¬
 this_item & (items list_position thru -1 of this_list)
 set this_list to the reverse of this_list
 end if
 else
 if the list_position is 1 then
 set the beginning of this_list to this_item
 else if the list_position is (the list_count + 1) then
 set the end of this_list to this_item
 else
 set this_list to (items 1 thru (list_position - 1) of this_list) & ¬
 this_item & (items list_position thru -1 of this_list)
 end if
 end if
 return this_list
end insert_listitem


Replacing List Items

You can replace an item in a list using the following syntax if you know the offset of the target item:

set this_list to {"Sal", "Sue", "Bob", "Carl"}
set item 3 of this_list to "Wanda"
return this_list
--> {"Sal", "Sue", "Wanda", "Carl"}

Replacing List Items by Matching

Use the following sub-routine to replace an item in a list if the position of the item to be replaced is not known. Note that the sub-routine has a passed parameter for indicating whether all matching items should be replaced or just the first occurrence:

set this_list to {"Sal", "Sue", "Bob", "Carl", "Sue"}
replace_matches(this_list, "Sue", "Wanda", false)
--> {"Sal", "Wanda", "Bob", "Carl", "Sue"}
set this_list to {"Sal", "Sue", "Bob", "Carl", "Sue"}
replace_matches(this_list, "Sue", "Wanda", true)
--> {"Sal", "Wanda", "Bob", "Carl", "Wanda"}
set this_list to {"Sal", "Sue", "Bob", "Carl", "Sue"}
replace_matches(this_list, "Bill", "Wanda", true)
--> {"Sal", "Sue", "Bob", "Carl", "Sue"}

Click to open example in the Script Editor applicationA sub-routine for replacing items in a list by matching:
 

on replace_matches(this_list, match_item, replacement_item, replace_all)
 repeat with i from 1 to the count of this_list
 set this_item to item i of this_list
 if this_item is the match_item then
 set item i of this_list to the replacement_item
 if replace_all is false then return this_list
 end if
 end repeat
 return this_list
end replace_matches