Each Expressions
Each
expressions let you clearly and concisely identify a set of values. They provide a powerful mechanism for selecting and manipulating multiple values at once. A single each expression processes a lot of work in a simple and readable way.
There are two ways of using each
expressions:
- To select or generate a list of values,
- To modify a set of values.
In addition, there is a closely-related set of expressions (called every
expressions), which are used to test whether a selected set of values all pass a given test.
These three mechanisms – "each value" expressions, "each container" expressions, and "every" expressions – have certain things in common.
- All three types of expressions operate on list items, or on chunks of text. While frequently used to work with lists, they can also be used to work with any chunk type: lines, text items, words, characters, or pattern matches or occurrences.
- All three types of expressions can use a
where
clause to select the set of values that they operate on. The where clause is optional. Without it, the expression applies to every item in a list or every chunk of text. When a where clause is used, it provides a clear and readable way to select a subset of values to operate on.
Using Each Expressions to Produce Values
An "each value" expression always produces a list of values, even when there is only a single value selected or no values at all (an empty list).
Example:
put each item of 1..50 where each is a multiple of 7 --> [7,14,21,28,35,42,49]
Example:
put each item of 1 to 20 where the square root of each is an integer --> [1,4,9,16]
Example:
put "Mary Mary quite contrary how does your garden grow" into rhyme
put each word of rhyme --> [Mary,Mary,quite,contrary,how,does,your,garden,grow]
put each word of rhyme where the length of each is 4 --> [Mary,Mary,does,your,grow]
put each word of rhyme where each ends with "ary" --> [Mary,Mary,contrary]
put the length of each word of rhyme where each ends with "ary" --> [4,4,8]
put each word of rhyme whose length is 4 and which contains "a" --> [Mary,Mary]
Example:
RunWithNewResults TestScript // TestScript is a variable containing the name of the script to run
put the result into Outcome
put the long name of each of the files of the folder of Outcome's logfile where each ends with ".png" into myfiles // Creates a list containing the file paths to all of the screenshots in the results
SendMail {To:"test@gmail.com",Subject:title & "---Test results" ,body:TestScript & "Results"& Outcome,attachment:Outcome's Logfile &&& myFiles}
Facts About Each
The result of an each
expression is always a list. Considering its simplest usage, an each
expression accesses each character, word, line, text item, or list item from a source value and creates a list containing those values.
A where
clause (or its variants, which
or whose
) lets you select items that meet some condition. Within a where
clause, the each
variable refers to each value from the source in turn. Only values for which the where
clause evaluates to true
are included in the resulting list.
Syntax:
each chunk of sourceValue {where conditional}
each chunk of sourceValue { { where conditional } }
each chunk of sourceValue { ( where conditional ) }
Use an each
expression with any chunk type (list items, text items, words, lines, or characters).
The conditional expression is usually an expression involving the special variable each
, which is set to each chunk of sourceValue in order to select which values to include in the resulting list. The where
clause can be enclosed in curly braces (or parentheses) for readability or separation from other parts of a statement (curly braces are recommended, for compatibility with every
expressions).
Each Expression within a Larger Expression
When an each
expression is embedded within a larger expression, other operators outside of the each
expression itself are applied to each of the values in the list generated by the each
expression rather than to the list as a whole.
Example:
put the length of each word of "four score and twenty"
-- The each expression generates the list ["four", "score", "and", "twenty"]
-- and then calls the length function on each item in the list, resulting in
-- a list of the individual word lengths. Displays '[4,5,3,6]'.
Limiting the Scope of an Each Expression
The fact that an each
expression spreads its influence to the enclosing expression, causing the entire expression to apply to each item in the resulting list, adds tremendously to its power. However, there are times when it is important to be able to limit this effect in order to get the desired result.
Example:
set text to "the flowers of the forest"
put the number of items in each word of text where the length of each is 3
-- The each expression returns the list ["the","the"] and then
-- the "number of items in" operator is applied to each item in this list,
-- resulting in two 1s (since the word "the" is a single item).
-- Displays the list '[1,1]'.
Use parentheses to limit the scope of the each
expression's influence.
Example:
put ["Mars","Venus","Saturn"] into planets
put the number of items in each item of planets where the length of each is greater than 4
-- Displays the list '[1,1]'
put the number of items in (each item of planets where the length of each is greater than 4)
-- Causes "the number of items in" to be applied to the result of the each expression
-- as a whole list, giving the number of words in the list with more than 4 letters.
-- Displays '2'.
Expanding Scope with For Each
Expressions
The fact that parentheses limit the scope of an each
expression restricts the type of usable expressions. For example, you cannot call a function using parentheses and have it apply to each value because the parentheses limit the scope of the each
expression. So the function is called for the resulting list as a whole rather than for each value.
A for each
expression can be used to overcome this problem.
Example:
put round(each,1) for each item of 2.2 to 3.1 by .25 -- Displays '[2.2,2.5,2.7,3]'
Here, an expression is given that uses the special each
variable, followed by an each
expression beginning with the words for each
. The expression that comes before for each
has no special restrictions, and can use the each
variable more than once. This example gives complete flexibility in the kinds of operations that can be performed.
Example:
set text to "an ancient anteater sat with my antiquarian aunt"
put "Longest words in text:"
get each & " has " & length(each) & " letters" for each word of text where length(each) > 4
put it joined by return
The above SenseTalk code displays as follows when executed:
Longest words in text:
ancient has 7 letters
anteater has 8 letters
antiquarian has 11 letters
Syntax:
resultExpression for each chunk of sourceValue {where conditional}
resultExpression ( for each chunk of sourceValue {where conditional} )
The conditional expression is usually an expression involving the special each
variable , which is set to each chunk of sourceValue in order to select which values to include in the resulting list.
resultExpression is usually also an expression using the special each
variable. It is evaluated for each of the values produced by the each
expression to produce the final list of values for the overall expression. The for each
clause can be enclosed in parentheses to enhance readability or provide separation from other parts of a statement.
Nested Each Expressions
An each
expression can be enclosed in another each
expression. Although this might become confusing, it might be useful when working with nested lists or other nested structures. For example, to obtain the lengths of each word (not for a single phrase, but for each of a series of phrases) you could do it as shown in the following example:
Example:
set phrases to {\{
universal truth
magic is in the eye of the beholder
all is fair in love and war
}}
put the length of each word of phrases
-- Displays a single list: '[9,5,5,2,2,3,3,2,3,8,3,2,4,2,4,3,3]'
put the length of each word of each line of phrases
-- Displays a nested list, one list for each line of phrases:
-- '[[9,5],[5,2,2,3,3,2,3,8],[3,2,4,2,4,3,3]]'
put the number of words of each line of phrases
-- Displays the list '[2,8,7]'
You can use where
clauses in nested each
expressions. You must be careful to match each where
to the nearest each
. For example, if you only wanted to see the word lengths for words that are longer than three characters, you might use the following example:
Example:
set myData to {\{
elephant
jelly jar
tea
}}
put the length of each word of each line of myData where true where length of each > 3
-- Uses "where true" to indicate interest in the lengths of the individual words
-- rather than the lengths of the lines. Displays the nested list '[[8],[5],[]]'
-- as only the first and second lines have any words with length greater than 3.
put the length of each word of each line of myData where length of each > 3
-- Validates the length of the lines rather than the length of the words within the line.
-- Displays the nested list '[[8],[5,3]]' which contains the lengths of the words only
-- from the lines that have lengths greater than 3.
Here, the first where
clause, where true
, is needed because without it, the other where
clause applies to each line, but you care about the lengths of the individual words, not the lengths of the lines.
Combined Each Expressions
You can combine two each
expressions as a part of a larger expression to multiply the effect, producing a nested list of results.
Example:
put each item of "A".."C" & each item of 1..4
-- Displays the nested list '[[A1,A2,A3,A4],[B1,B2,B3,B4],[C1,C2,C3,C4]]'
Example:
put each item of 1..3 times each item of 1..3 into timesTable
-- Stores the nested list '[[1,2,3],[2,4,6],[3,6,9]]' into a variable
Counter
in Each Expressions
When you use the counter
function with an each
expression, the function evaluates to the number of the current item within the source. See Repeat Loops for more information.
Example:
put each char of "abcdefg" & counter()
-- Associates a number, according to the value of the counter,
-- with each character of the string.
-- Displays the list '[a1,b2,c3,d4,e5,f6,g7]'.
This ability also means that if you need the counter
value from an enclosing loop inside an each
expression, you need to first assign the counter
value to a variable.
You can use repeatIndex
as a synonym for the counter
function.
Example:
set FarmAnimals to {\{
pig
cow
chicken
}}
put each line of FarmAnimals & " is on line " & the counter
-- Displays the list '[pig is on line 1,cow is on line 2,chicken is on line 3]'
Repeat With Each
Repeat with each
is a type of repeat loop that, when combined with each
expressions, easily evaluates a string, then immediately performs operations against the resulting list's items during each iteration.
Example:
repeat with each item of ["dog","cat","horse"] which starts with "c" -- Evaluates the original list from which it creates new list '[cat]', and then iterates with each item of the new list
put it & " meows" -- Displays 'cat meows'
end repeat
Example:
repeat with each word of "To infinity and beyond!" whose length is greater than 3
log it -- Logs "infinity" on the first iteration and "beyond!" on the second iteration
typetext it
end repeat
Using Each Expressions to Modify Values
When an Each expression is used in a context where a value is expected (known as an "each value" expression), it produces a list of values, as described under Using Each Expressions to Produce Values. An Each expression can also be used in a context where a destination container is expected (known as an "each container" expression). By "container" we mean a value that is modified by a command. When used in this way the each expression can select and provide a list of values that will each be modified by the command.
For example, consider the add command, which is expressed in the form add
aValue to
aContainer. Typically, the container is a variable, whose value is modified by having aValue added to it.
add 7 to total
Using an each
expression in place of the container (total
, in this case) lets you modify an entire set of values at once:
add 7 to each item of vacationTotals
Using a where
clause lets you select which values will be modified:
add 7 to each item of vacationTotals which is less than 20
The commands where an "each container" expression can be used include: Set
, Put
, Add
, Subtract
, Multiply
, Divide
, Insert
, Push
, Pop
, Pull
, Split
, Join
, Replace
, Sort
, Read
, Reverse
, Shuffle
, Add Properties
, Remove Properties
, Replace Properties
, Retain Properties
, Rename Properties
.
Example
set each item of grandTotals to zero -- sets each item in a list
set numbers to [4,1,26,33,8,72,5,12]
multiply each item of numbers {which is a multiple of 3} by 100
put numbers --> [4,1,26,3300,8,7200,5,1200]
set numbers to [408,22,7,123,45,9,265,38]
pull each item of numbers which is greater than 100 into higherNumbers
put numbers --> [22,7,45,9,38]
put higherNumbers --> [408,123,265]
Example
set sentence to "The rain in Spain falls mainly in the plain"
set each word of sentence {where each contains "ain"} to "[" & each & "]"
put sentence —> "The [rain] in [Spain] falls [mainly] in the [plain]"
Example
rename each item of recordList using internalRecordNames
Using Every Expressions to Test Values
An every
expression is similar to an each
expression. Where an each expression returns a list of values, an every expression returns a single value of True or False, indicating whether every evaluated expression is true, or not.
Because an every expression always evaluates as True or False, they are typically used as the condition of an if statement. For example, to test whether all values in a list of numbers are greater than 0, you could say:
if every item of numList is greater than 0 then ...
While every expressions are different from each expressions in the value that they return, they are alike in that both can use a where
clause (or which
or whose
) although in every expressions these must be enclosed in {
}
. Also, both types of expressions "expand" to include the surrounding operators in an expression unless contained by parentheses.
Example
Check the score property of every property list in a list called grades.
the score of every item of grades is at least 90
There are 4 different varieties of every
expression (although only 2 of them actually use the word "every", but their behavior and use is so similar that we group them all together):
- every: Returns true if and only if every selected entry is true;
- not every: Returns true if at least one selected entry is not true;
- at least one: Returns true if at least one selected entry is true (and false if none are true);
- none of or not one of: Returns true if none of the selected entries are true.
All of these expressions will stop evaluating values as soon as the truth or falsity of the expression can be determined (for example, if the first selected entry evaluated by every
is false, it is known that the overall result will be false so no other entries are evaluated).
Syntax:
every {single} chunkType [of | in] sourceValue { { [where conditionWithEach | which operator value | whose propertyCondition] } } operator valuenot every {single} chunkType [of | in] sourceValue { { [where conditionWithEach | which operator value | whose propertyCondition] } } operator value
at least one {of {the}} chunkType [of | in] sourceValue { { [where conditionWithEach | which operator value | whose propertyCondition] } } operator value
[not one {of {the}} | none of {the}] chunkType [of | in] sourceValue { { [where conditionWithEach | which operator value | whose propertyCondition] } } operator value
Examples:
set numList to [1,3,7,12,43,99]
put every item of numList is a number —> True
put not every item of numList is divisible by 3 —> True
put at least one item in numList is divisible by 3 —> True
put at least one item in numList is 77 —> False
put not one item in numList is less than 0 —> True
put none of the items in numList is equal to 500 —> True
Where Clauses
A where
clause (or which
or whose
) lets you select items that meet some condition. Within a where
clause, the each
variable refers to each value from the source in turn. Only values for which the where
clause evaluates to true
are included in the resulting list.
The term which
can be used in place of where each
. So these two expressions are equivalent:
each item of numList where each is more than 99
each item of numList which is more than 99
Similarly, whose
can be used in place of where each's
. So these two expressions are equivalent:
each item of cards where each's suit is "clubs"
each item of cards whose suit is "clubs"
Which
and whose
can also be used within a more complex where clause in place of the terms each
or each's
, respectively. So these two expressions are equivalent:
each item of nums where each is more than 99 and each is an even number
each item of nums which is more than 99 and which is an even number
For added clarity, the where
clause can be enclosed in curly braces (parentheses can also be used for each
expressions, but are not recommended). To avoid ambiguity in every
expressions (which always end with a comparison to another value), where
clauses used with every
expressions must be enclosed in curly braces. Because of this, both for consistency and added readability, it is suggested that you adopt the habit of using curly braces around all where
clauses.