[AMG] I wasn't quite satisfied with '''[[listc]]''', [Todd Coram]'s [list comprehension] procedure, so I adapted it into something far worse. Behold! proc lcomp {expression args} { # Check the number of arguments. if {[llength $args] < 2} { error "wrong # args: should be \"lcomp expression var1 list1\ ?... varN listN? ?condition?\"" } # Extract condition from $args, or use default. if {[llength $args] % 2 == 1} { set condition [lindex $args end] set args [lrange $args 0 end-1] } else { set condition 1 } # Collect all var/list pairs and store in reverse order. set varlst [list] foreach {var lst} $args { set varlst [concat [list $var] [list $lst] $varlst] } # Actual command to be executed, repeatedly. set script {lappend result [subst $expression]} # If necessary, make $script conditional. if {$condition ne "1"} { set script [list if {[expr $condition]} $script] } # Apply layers of foreach constructs around $script. foreach {var lst} $varlst { set script [list foreach $var $lst $script] } # Do it! set result [list] {expand}$script ;# Change to "eval $script" if using Tcl 8.4 or older. return $result } ---- Mainly I didn't like '''[[listc]]''''s method of constructing its '''$foreachs''' variable (which I have named '''$script''' in my code), so I switched it around to be built inside-out rather than left-to-right. I start by putting together the actual command that'll be run by the tangled nest of [[[foreach]]] constructs; then I tack on '''[[foreach]]'''s and [[[if]]]s with the aid of [[[list]]]. Magically I no longer have to worry about matching braces, thus shortening my code into the sorry heap you see above. Next up, I changed [[[eval]]] to [[[subst]]] and [[[expr]]], since I felt that all '''$expression'''s would use substitution and all '''$condition'''s would be boolean expressions. Especially nice is the ability to use [[...]] substitutions with both [[[subst]]] and [[[expr]]], so the old behavior can be had by wrapping the parameter with [[ and ]]. Lastly (unless I missed something), I dropped the '''<-''' sugar. I didn't much care for it, since [[foreach]] itself doesn't use it. You can re-add it if you like by changing "% 2" to "% 3" and "< 2" to "< 3" and the first instance of "var lst" to "var <- lst". ---- Examples? I'll start by listing Todd's examples modified to work with [[lcomp]]. set i [list 1 2 3 4 5 6] set l2 [lcomp {$i} i $i] puts "A copy of the list: $l2" set dbl [lcomp {[expr {$n*2}]} n $i] puts "Double values from list: $dbl" set evn [lcomp {$i} i $i {$i%2 == 0}] puts "Only even numbers: $evn" proc digits {str} { set lstr [split $str ""] return [lcomp {$d} d $lstr {[string is digit $d]}] } puts "Just digits from (703)-999-0012= [digits (703)-999-0012]" set names1 [list Todd Coram Bob Jones Tim Druid] set lf [lcomp {$l,$f} {f l} $names1] puts "From ($names1): Last,first = $lf" set l3 [lcomp {$f} {f l} $names1 {[string match "T*" $f]}] puts "From ($names1): Only names starting with 't': $l3" set l4 [lcomp {[list $n1 $n2]} n1 [list a b c] n2 [list 1 2 3]] puts "Create a matrix pairing {a b c} and {1 2 3}: $l4" Here are some more: lcomp {$x} x {0 1 2 3} ;# 0 1 2 3 lcomp {$y $x} {x y} {0 1 2 3} ;# {1 0} {3 2} lcomp {[expr {$x ** 2}]} x {0 1 2 3} ;# 0 1 4 9 lcomp {[expr {$x + $y}]} x {0 1 2 3} y {0 1 2 3} ;# 0 1 2 3 1 2 3 4 2 3 4 5 3 4 5 6 lcomp {$x} x {0 1 2 3} {$x % 2 == 0} ;# 0 2 ---- Practical uses? The following deletes all images named by any elements in the '''images''' array: image delete {expand}[lcomp {$val} {key val} [array get images]] I'll come up with more later as I use [[lcomp]] more in my own code. ---- [[ [Category Concept] | [Arts and crafts of Tcl-Tk programming] ]]