Tinderbox v9 Icon


Operator Type: 

Operator Scope of Action: 

Operator Purpose: 

Operator First Added: 

Operator Last Altered: 

Operator Uses Loop Variable Argument: 

 Function  [other Function type actions]

 Item  [operators of similar scope]

 Data manipulation  [other Data manipulation operators]


 As at baseline

 [More on loop variable arguments]

List/Set.each(loopVar){ action(s) }

This allows you to operate in turn on each item in a list or set. Put another way you 'iterate;' or loop though, every item in the list evaluating any code inside the { } brackets. The user-defined (i..e. named by the user) loopVar can be used inside the loop to refer to the value of the current list item value being iterated. If the list is a list of path info (or $IDString, $ID, or unique $Name) then in-loop loopVar can be used for offset addressing the note at that path via an attribute offset argument, i.e. $SomeAttribute(loopVar).

What is a loop variable?

For example, for a note with a list of values in $MyList:

$MyList.each(x){$Result=$Result +x+"\n" ;} 

will replace the current note's value of $Result with a list of every value from $MyList, but each on its own line. The loopVar, here the in-loop variable 'x', is simply the string defined in .each(), and is case-sensitive and a '$' prefix is not required for in-loop references to the loop variable. For most Tinderbox users, a more readable/understandable version of the above is this:

		$Result=$Result +aString+"\n" ;

What has changed? Firstly, the loop has been broken out onto speaker lines and in-loop code indented. Tinderbox ignores line breaks and white space between operators and values so both the above seems the same to the parser. Secondly, the obfuscatory 'x' loopVar name has been changed to a more descriptive 'aString' based on the presumption that $Result is a String (it cannot be a Number because Number-type data cannot have line breaks within a single value) and, for the calling note, we are compiling a string the list $Result values.

Thus .each(loopVar) would iterate using references to loopVar, and thus .each(Y) would iterate using references to 'Y', whilst .each(Abracadabra) would iterate using references to 'Abracadabra', and so forth. Consider making the loop variable something clear to both the user and to Tinderbox. In the trivial example above, 'x' seems pretty clear but might be misread by the users—in a mathematical context—as a multiplication symbol; Tinderbox will not be confused as it uses * for multiplication but consider how something like 'LoopVar' might be clearer. By the same token make sure the loop variable name does not clash with existing attribute names or attribute string values of the same name that might be used as part of the data being processed.

A variable declared using var() may be altered from within the scope of an .each() loop.

If $Total is a numeric attribute and $MyList is a list of numbers:

		$TotalNumber += aNumber*aNumber; // parentheses not required but can be useful if calculation is not simple


computes the sum of the squares of the values in $MyList and stored it in $TotalNumber. As the list is a list of numbers, the user-chosen loopVar name used is 'aNumber'.

Note: remember that you, the user, choose the actual name of loopVar in your own code. It can vary per use, as in the examples on this page.

The loopVar can be a path and this can be used as a variable designator for attribute offset addressing inside the loop:

		$Text += "\n"+$Text(aPath);

In the above, a list is created on the fly of the current note's children. Then the current note's $Text is appended, for each child, with a line and the child's $Text. As the list is a list of paths, the user-chosen loopVar name used is 'aPath'. Thus for each iteration of the loop aPath's value is being used to provide the offset address in the loop to $Text(loopVar).

If it is desired to iterate a list a particular number of times, another approach to the above is to use the range '...' operator which can be used to provide a numbered loop variable (see).

After each iteration of an each(){} loop, accumulated back-references are cleared. Formerly, back-references from each iteration were retained for the lifetime of the loop, making it very difficult to retrieve the desired reference.

To test for position in a loop, i.e. detecting if processing the first or last items, see List/Set.first() and List/Set.last().

To get a random item from a list without needing to use a loop, see List/Set.randomItem().

A worked example of looping is here.

Examples of using action() within a loop to create attribute references is given here.