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]'