New LinkAdded April 2018
Adding, deleting or modifying keys while iterating will render the iterator unpredictable, and thus should be strictly avoided. You may, however, modify the values of the key-value pairs as you iterate through them, either by using the .key() function or by assigning a new value to the iterator directly; see History below. For example, the loop below shows both methods of modifying the value of each element by prefixing it with "Beautiful" and folding the preexisting part to upper case, assuming varstr elements:
foreach $$i in $capitals() ! fwd iterator
$capitals(.key($$i)) = "Beautiful " + ucs($$i) ! method 1
! or...
$$i = "Beautiful " + ucs($$i) ! method 2
next $$i
In the following example, we copy a portion of the ordered map $cap1 (i.e. the capitals of the States starting with "C") to a new ordered map $cap2. Note that we can't take advantage of startkey to jump directly to the C's because it only works when there is an exact match.
dimx $cap1, ordmap(varstr;varstr)
dimx $cap2, ordmap(varstr;varstr)
map1 state$,s,40
...
foreach $$i in $cap1()
state$ = .key($$i)
if state$[1,1] = "C" then
$cap2(state$) = $$i
repeat
elseif state$ >= "D" then
exit
endif
next $$i
Note that in the above example, we didn't have to introduce the temporary variable state$, but doing so probably increases efficiency by eliminating redundant use of the .key($$i) operation. Ordered map operations are extremely efficient given what they involve, but they are still considerably more costly than ordinary variable or array references, particularly as the map gets large. Also note that as with other control loops, the control statements EXIT and REPEAT are available.
Notes:
• | This technique works with all collection types (ORDMAP, ORDMAPM, MLIST). |
• | In the case of ORDMAPM, it is the only way to change the value of an existing element for which there are duplicate keys. |
• | In the case of ORDMAP, the direct assignment to the iterator in the above example would be equivalent to ... |
$foo(.key($$i)) += "-updated"
... except much faster, since the key lookup, deletion, and re-addition steps are all eliminated. |
• | In the case of MLIST, it eliminates the need for the .ref($$i) function, (which is now effectively deprecated). |
• | The iterator is only writeable when it appears on the left side of the equals sign in an assignment statement. In all other cases, particularly when passing an iterator as an argument to a function, it remains read-only. |
History
2018 May, A-Shell 6.5.1636, compiler edit 859: the starting key in a FOREACH statement may now be any kind of expression. Previously, it only allowed a simple variable or a literal string or numeric constant; numeric literals were allowed but weren't converted to string and thus typically failed to match any items in the map.
2018 April, A-Shell 6.5.1633: Writeable Interators added to A-Shell.