'''lolcat''' is an [Additional list functions%|%additional list function] which [aspect] uses almost every day. Once you come to love it, you will too! ** See Also ** [fptools]: Provides `lmultimap`, which offers a different way to have multiple results from mapping over a single list. [map in functional programming]: Another small but powerful variation on `[lmap]`. ** Description ** '''lolcat''' is a portmanteau of `[lmap]`, `[{*}]` and `[concat]`: ====== proc lolcat args { concat {*}[uplevel 1 ::lmap $args] } ====== It's useful in cases whene using `[lmap]` but the body might need to yield multiple results for a single iteration. Here's a simple example: ====== % lolcat {x y} {1 2 3 4} {list $y $x} 2 1 4 3 % lolcat x {1 2 3 4} {if {$x%2} {list $x $x} else {list $x}} 1 1 2 3 3 4 ====== `[concat]` joins its arguments, adding whitespace in between, and `concat {*}$ls` receives the elements of `$ls` as its arguments. Thus, `concat {*}$ls` removes one layer of structure from the original list. ====== % concat {*}{{1 2} {3 4 5} {6 {7 8}} 9} 1 2 3 4 5 6 {7 8} 9 # equivalently: % concat {1 2} {3 4 5} {6 {7 8}} 9 1 2 3 4 5 6 {7 8} 9 ====== [PYK] 2016-01-09 cautions: `lolcat` requires that the result of the `[lmap]` body be a list, not a simple value. Otherwise, data might get munged. ====== set res [lolcat {x y} {1 2 3 4 5 6} { if {$x == 3} { # skip 4 return -level 0 {answer 3} } else { list "answer $y" "answer $x" } }] ====== Output: ======none {answer 2} {answer 1} answer 3 {answer 6} {answer 5} ====== The desired output would normally be ======none {answer 2} {answer 1} {answer 3} {answer 6} {answer 5} ====== and the way to achieve that would be `return -level 0 [list {answer 3}]` [PYK] 2016-04-19: `[join]` is a little more concise and efficient, and the `1` in `[uplevel]` isn't strictly necessary since `lmap` can't be interpreted as a level: ====== proc lolcat args { join [uplevel ::lmap $args] } ====== ---- One neat extension on lolcat is '''dictify''': ====== proc dictify {cmdPrefix ls} { lolcat x $ls { list $x [uplevel 1 $cmdPrefix [list $x]] } } ====== This allows you to make a [dict]ionary whose keys are a list, and values are the result of evaluating a command on each element. ====== % dictify {expr 2**} {1 2 3 4 5} 1 2 2 4 3 8 4 16 5 32 ====== Or more elaborately: ====== % proc pdict d {array set {} $d; parray {}} % pdict [dictify {tcl::pkgconfig get} [tcl::pkgconfig list]] debug = 0 threaded = 1 profiled = 0 64bit = 0 optimized = 1 mem_debug = 0 compile_debug = 0 compile_stats = 0 libdir,runtime = /home/tcl/lib bindir,runtime = /home/tcl/bin scriptdir,runtime = /home/tcl/lib/tcl8.6 includedir,runtime = /home/tcl/include docdir,runtime = /home/tcl/man libdir,install = /home/tcl/lib bindir,install = /home/tcl/bin scriptdir,install = /home/tcl/lib/tcl8.6 includedir,install = /home/tcl/include docdir,install = /home/tcl/man ====== The name comes courtesy [hypnotoad] - previously I called this procedure '''lconcat''', which is obviously a terrible name, and I only stuck with for lack of a better alternative. It took the toad's genius to find this proc's correct name, which just goes to show: give a dog a bad name, and it will stick ... but a cat can change its stripes! ** Similar Works ** [AMG]: [[lolcat]] resembles [[[lcomp]]]: ====== % lolcat {a b} {1 2 3 4} {list $b $a} % lolcat a {1 3} b {2 4} {list $b $a} % lcomp {$b} {$a} for {a b} in {1 2 3 4} % lcomp {$b} {$a} for a in {1 3} and b in {2 4} ====== All return `2 1 4 3`. The differences are: %|[[lolcat]] |[[lcomp]] |% &|Result generator is last argument|Result generator is first argument(s) |& &|Result generator is one argument |Result generator is one or more argument(s)|& &|Result generator is Tcl script |Result generator is [expr] expressions |& &|No noise words |Supports numerous tokens such as '''for''' |& While I'm on the subject, [Brush] offers (will offer) capability very similar to [[lcomp]], though the language-level syntax is different: ====== % collect b a for (&a &b) in (1 2 3 4) % collect b a for &a in (1 3) and &b in (2 4) ====== <> Command