The List/Set.each() function can be used to iterate lists. It works like a 'for each' method commonly used in programming and scripting whereby each and every item in the source list is processed using the in-loop code.
Using a list item more than once per loop
Assume your data is in a List or Set type attribute. In this case $MyList contains the values cow/dog/eel. Assume it is necessary to turn that into an HTML select list like this:
<select>
<option value="cow">cow</option>
<option value="dog">dog</option>
<option value="eel">eel</option>
</select>
Notice how in the output above each source list item is used more than once. However, using format() or List.format() you can only wrap each list item once. So other than doing iterative list formatting, which can get complex, .each() offers a way around this. Use the following $Rule, line breaks and indentation are just for clarity:
$MyList =;
$MyList.each(X) {
$MyString = '<option value="'+X+'">'+X+'</option>';
$MyList = $MyList + $MyString;
};
$Text = "<select>\n"+$MyList.format("\n")+"\n</select>";
Shorter version, without the in-loop caching of the concatenated per-item string (see bullet #3 below for the rationale):
$MyList =;
$MyList.each(X) {
$MyList = $MyList + ("<option>"+X+"</option>");
};
$Text = "<select>\n"+$MyList.format("\n")+"\n</select>";
Notes:
- $MyList must be reset (to an empty list) before the loop otherwise each time the Rule fire the loop adds to existing $MyList data rather than build a new set.
- Everything between the { } is runs as the loop. Here the closing } has a semi-colon after it as another discrete section of code follows it.
- Ordinarily, one could simply put parentheses around the string literals to concatenate them before passing a single string into $MyList. This works as long as the string literals to concatenate do not contain single or double quotes, or, if double quoted enclosed strings contain single quotes. But, an edge case occurs where single-quote-enclosed strings contain any double-quotes; in such cases an 'interim' string attribute is needed to ensure the sub-strings are correctly concatenated before the data is passed to $MyList.
- As a string attribute only contains one value, adding a new one replaces the old. Thus $MyString does not need to be reset before the loop unlike a set or list such as $MyList.
- Note that for the final concatenation .format() can be used as each list item is used only once in the resulting output. The closing select tag must be preceded with a '\n' line break as the .format()'s join only adds the concatenation string between each item in $MyList and a lone break is needed after the last option close tag.
Detecting first or last loop items
This is discussed separately in detecting first or last item context in loops. Also see: List/Set.first and List/Set.last.
Adding output joins in-loop
Adding a loop counter
By default .each() processes every list item. But what if you only want do something with the Nth item or perhaps only even numbered ones? In that case it is necessary to create a loop counter, and iterate in-loop. For instance, the following sums the value of odd-numbered items of $MyList onto the existing value of $MyNumber:
$MyCountNum = 0;
$MyList.each(ListItem) {
if(mod($MyCountNum,2)==0) {
$MyNumber = MyNumber + ListItem;
};
$MyCountNum = $MyCountNum + 1;
};
Notes:
- Set the counter ($MyCountNum) to zero (or just reset the attribute) before starting the loop.
- Tinderbox list values number upwards from zero (e.g. as seen if accessing data via the List.at() function). Here, think of list item #1 being
1
, then set $MyCountNum to1
before the loop and test formod($MyCountNum,2)!=0
. - Note that list.at() is read-only so you cannot use code like
$MyList.at($MyCountNum) = ListItem;
An alternate method is to use the range operator (see example).
Using a path variable
The loop variable can itself be a path and this be used as a variable designator allowing attribute offset addressing inside the loop:
$Text=""; collect($Overdue,$Path).each(x){
$Text = $Text+":"+$Text(x);
};
In the above, the 'x' variable is a $Path value and is being used to provide the offset address argument in the loop.
Using a variable within a loop
A variable created by var can be altered from within an .each() loop, as shown here.
Creating an $AttributeReference within a loop