foreach - Iterate over all elements in one or more lists '''foreach''' ''varname list body'' ** Synopsis ** '''foreach''' ''varlist1 list1 ?varlist2 list2 ...? body'' : '''foreach''' ''varlist list body'' http://purl.org/tcl/home/man/tcl8.4/TclCmd/foreach.htm : '''foreach''' ''varlist1 list1'' ?''varlist2 list2 ... varlistn listn''? ''body'' The '''foreach''' command implements a loop where the loop variable(s) take on values from one or more lists. In the simplest case there is one loop variable, ''varname'', and one list, ''list'', that is a list of values to assign to ''varname''. The ''body'' argument is a Tcl script. For each element of ''list'' (in order from first to last), '''foreach''' assigns the contents of the element to ''varname'' as if the '''[lindex]''' command had been used to extract the element, then calls the Tcl interpreter to execute ''body''. Occasionally developers are surprised to discover that if ''list'' is modified within the confines of the ''body'' 's code, ''varname'' never reflects the change. This is due to the tcl parser having a fixed copy of the elements of ''list'' in memory and not referring to the actual variable during the assignment of values to ''varname'' during the loop construct. In the general case there can be more than one value list (e.g., ''list1'' and ''list2''), and each value list can be associated with a list of loop variables (e.g., ''varlist1'' and ''varlist2''). During each iteration of the loop the variables of each varlist are assigned consecutive values from the corresponding ''list''. Values in each ''list'' are used in order from first to last, and each value is used exactly once. The total number of loop iterations is large enough to use up all the values from all the value lists. If a value list does not contain enough elements for each of its loop variables in each iteration, empty values are used for the missing elements. [http://www.tcl.tk/man/tcl/TclCmd/foreach.htm%|%official reference documentation]: The '''[break]''' and '''[continue]''' statements may be invoked inside ''body'', with the same effect as in the '''[for]''' command. '''Foreach''' returns an empty string. (From: [TclHelp]) ---- It is a popular [idiom] to use the varlist assignments to split up a list. The body in such cases would just be ''break'' to stop foreach running into a second round: To stride through a list, picking up every n'th item, a dummy variable like `$-` foreach {first second third} $list break ;# RS You might as well swap variables with that: foreach {a b} [list $b $a] break a slightly faster version is foreach a $b b $a break Get every second element of a list with the following ("-" being a fancy variable name that indicates it will not be used): foreach {- i} $list {...} To save an array to a file: ---- 'Foreach' is also a convenient way to work with Tcl's associative arrays. For instance, you can save an array to a file as a Tcl script by using: ====== foreach { key value } [array get myArray] { puts $myFile [list set myArray($key) $value] } Of course, you could have written: If you want the keys alphabetized, then foreach { key } [lsort -dictionary [array names myArray]] { puts $myFile [list set myArray($key) $myArray($key)] } ====== puts $myFile [list array set myArray [array get myArray]] but when editing such a file, the lack of line endings might give your text but that style creates scripts which cause trouble in many text editors. To save an array to a file, ordering it alphabetically by key: ---- Applying 'foreach' to the result of the 'bbox' command in a canvas is often a convenient way to create canvas layouts. The following script gives the idea. ====== grid [canvas .c -width 400 -height 300 -bg gray85] set i [.c create text 200 50 -text "One" -anchor n] foreach item { Two Three Four } { foreach { - - - y } [.c bbox $i] break set nexty [expr { $y + 50 }] .c create line 200 $y 200 $nexty -arrow last set i [.c create text 200 $nexty -text $item -anchor n] } [KPV]: A similar example illustrates finding the dimensions of a canvas to A similar example is when I wanted to find the dimensions of a canvas but I wanted to shrink the size to provide a margin around the layout. [KPV] ====== # Get canvas dimensions shrunk by some foreach who {x0 y0 x1 y1} val [.c cget -scrollregion] d {30 30 -30 -30} { set $who [expr {$val + $d}] } [http://img684.imageshack.us/img684/1269/image71.gif] ---- '''One-time loop:''' You can use [foreach] also for a loop that runs exactly once, and you're not interested in the iterator, but get the side effect that you can "jump out" of the body with [break] or [continue] (seen in a c.l.t post by [Bruce Hartweg]): foreach _ _ { if {$somecondition} break # some other processing if {$someothercondition} break # still more processing } } This is an alternative to nested `[if]` structures. Helps you avoid nested [if] structures. [RS] is not sure whether to recommend this style.. but proof again that you can do more with Tcl than you'd imagine...;-) Well, hell, then add some sugar: [RS] is not sure whether to recommend this style.. but proof again that you can interp alias {} breakable {} foreach _ _ breakable { ;# or 'fragile'? if {$somecondition} break # some other processing if {$someothercondition} break # still more processing } } Or, to make your intention clearer: ====== interp alias {} make {} foreach make or break { } } [AMG]: This is like the '''`do {...} while (0);`''' idiom in [C], which is ---- [SS] wonders why foreach doesn't return the result of the last executed command. It can be useful for programmers using Tcl in a functional style. The same also apply to [for]. [CL] likes the idea. [rmax]: Another useful return value (maybe even closer to functional [rmax] - Another useful return value (maybe even closer to functional programming) could be the unprocessed part of the list if a break occured in the loop body. ====== foreach {a b c} $args break set args [lrange $args 3 end] This could be done easier and would be less error prone if foreach returned the This could be done easier and would be less error prone if foreach returned the tail of the list: ====== set args [foreach {a b c} $args break] Of course, this feature can only work in a useful way if foreach was called Of course this feature can only work in a useful way if foreach was called with just one list. ====== [SS]: Yep [rmax], my past idea evolved almost exactly into a new idea similar See also: * [for] * [while] ---- [[ [Tcl syntax help] | [Arts and Crafts of Tcl-Tk Programming] | [Category Command] ]]