Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/Additional+list+functions?V=168
QUERY_STRINGV=168
CONTENT_TYPE
DOCUMENT_URI/revision/Additional+list+functions
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR172.69.6.241
REMOTE_PORT10674
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR18.223.159.195
HTTP_CF_RAY876243828e136173-ORD
HTTP_X_FORWARDED_PROTOhttps
HTTP_CF_VISITOR{"scheme":"https"}
HTTP_ACCEPT*/*
HTTP_USER_AGENTclaudebot
HTTP_CF_CONNECTING_IP18.223.159.195
HTTP_CDN_LOOPcloudflare
HTTP_CF_IPCOUNTRYUS

Body


Error

Unknow state transition: LINE -> END

-code

1

-level

0

-errorstack

INNER {returnImm {Unknow state transition: LINE -> END} {}} CALL {my render_wikit {Additional list functions} '''Additional\ \[list\]\ functions'''\ \ is\ a\ guide\ to\ pages\ that\ provide\ commands\ and\nscripts\ or\ present\ methods\ for\ manipulating\ \[list%|%lists\].\n\n\n\n**\ Command\ Suites\ **\n\nCollections\ of\ list\ commands.\n\n\ \ \ \[aqtools\]:\ \ \ \n\n\ \ \ \[ExtraL\]:\ \ \ \n\n\ \ \ \[fptools\]:\ \ \ `lcompare`,\ `lempty?`,\ `lmultirange`,\ `lreduce`,\ `lsample`,\ `lshift!`,\ `match`\ (for\ \[pattern\ matching\]\ on\ lists)\ and\ others.\n\n\ \ \ \[https://web.archive.org/web/20080625075946/http://www.han.de/~racke/jultaf/jultaf.html%|%Jumble\ Library\ for\ Tcl\ and\ Friends\],\ by\ Stefan\ Hornburg:\ \ \ `shift`,\ `pop`,\ `append`,\ `assign`,\ `match`\n\n\ \ \ \[Listx\]:\ \ \ Provides\ the\ essential\ extended\ set\ of\ list\ operations.\ Today,\ most\ are\ in\ Tcl\ itself.\n\n\ \ \ \[Listex\],\ by\ \[Stuart\ Cassoff\]:\ \ \ `lPluck`,\ `lDivide`,\ `lDivideAtStr`,\ `lUInterleave`,\ `lMaxelementLength`.\n\n\ \ \ \[ftp://ccfadm.eeg.ccf.org/pub/ctk/mtcl.tar.gz%|%mtcl\]:\ \ \ (\[HaO\]\ 2010-08-24:\ dead\ link\ for\ me)\n\n\n\ \ \ \[http://www.purl.org/net/akupries/soft/pool/index.htm%|%Pool\]:\ \ \ \n\n\ \ \ \[http://www.purl.org/net/akupries/soft/pool/pkg_Pool_Base.htm%|%Pool_Base\]:\ \ \ \n\n\ \ \ \[tcllib%|%tcllib's\]\ \[struct::list\]:\ \ \ \n\n\ \ \ \[TclX\]:\ \ \ Search\ the\ \[http://www.tcl.tk/man/tclx8.2/TclX.n.html%|%documentation\]\ for\ ''LIST\ MANIPULATION\ COMMANDS''.\n\n\ \ \ \[underscore.tcl\]:\ \ \ \n\n\ \ \ \[ycl\]::list:\ \ \ provides\ commands\ such\ as\ `dedent`,\ `any`,\ `all`,\ `are`,\ `filter`,\ `pick`,\ `\[scripted\ list%|%sl\]`,\ and\ `which`.\n\n\n\n**\ Modification\ Commands\ **Commands\ that\ modify\ the\ content\ of\ a\ list.\n\n\ \ \ *\ \[lpop\]:\ \ \ \n\ \ \ \[lpop\]:\ \ \ \n\n\ \ \ \[lremove\]:\ \ \ \n\n\ \ \ \[lshift\ -Adding\ Unique\ Items\ to\ Lists\ of\ Fixed\ Length\]:\ \ \ \n\n\n\n\ \ \ *\ \[another\ list\ comprehension\]:\ \ \ \n\ \ \ *\ \[Finding\ a\ sublist\]:\ \ \ \n\n\ \ \ \[another\ list\ comprehension\]:\ \ \ \n**\ Traversal\ Commands\ **Commands\ that\ visit\ elements\ in\ a\ list.\n\ \ \ \[Finding\ a\ sublist\]:\ \ \ \n\n\ \ \ \[lazy\ lists\]:\ \ \ \n\n\ \ \ \[List\ Comprehension\]:\ \ \ \n\n\ \ \ \[list\ map\ and\ list\ grep\]:\ \ \ two\ operations\ implemented\ (over-)simply\ in\ Tcl.\n\n\ \ \ \[lswitch\]:\ \ \ Like\ `\[switch\]`,\ but\ each\ ''pattern''\ is\ a\ list\ of\ patterns\ to\ match\ against\ the\ item\ in\ ''string''\ at\ the\ corresponding\ position.\ All\ switch\ options\ are\ supported.\n\n\ \ \ \[range\],\ by\ \[Salvatore\ Sanfilippo\]:\ \ \ \[Python\]-like\ range\ operation.\n\n\ \ \ \[Recursive\ list\ searching\]:\ \ \ \n\n\ \ \ \[Striding\ a\ list\]:\ \ \ \n\n\n\n\ \ \ *\ \[Use\ while\ to\ iterate\ over\ a\ list\]:\ \ \ \n\n\n\ \ \ \[Use\ while\ to\ iterate\ over\ a\ list\]:\ \ \ \n**\ Reording\ Commands\ **Commands\ that\ reorder\ the\ elements\ of\ a\ list.\n\n\ \ \ *\ \[randomizing\ a\ list\]:\ \ \ \n\ \ \ *\ \[Shuffle\ a\ list\]:\ \ \ \n\ \ \ *\ \[Shuffle\ a\ list:\ graph\ results\]:\ \ \ \n\ \ \ *\ \[Shuffling\ a\ list\]:\ \ \ \n\ \ \ \[randomizing\ a\ list\]:\ \ \ \n\ \ \ *\ \[list\ stripping\]:\ \ \ \n\ \ \ \[Shuffle\ a\ list\]:\ \ \ \n\n\ \ \ \[Shuffle\ a\ list:\ graph\ results\]:\ \ \ \n\ \ \ \n\ \ \ \[Shuffling\ a\ list\]:\ \ \ \n\n\ \ \ \[Sorted\ Lists\]:\ \ \ \n\n\ \ \ \[lrotate%|%Rotate\ a\ list%|%\]:\ \ \ \n\n\ \ \ *\ \[List\ trim\]:\ \ \ \n\ \ \ *\ \[lsplit\]:\ \ \ creates\ two\ lists\ from\ a\ single\ list\ and\ a\ test\ expression\ \n\ \ \ *\ \[MakeRanges\]:\ \ \ Takes\ a\ list\ of\ numbers\ and\ makes\ them\ into\ a\ a\ list\ of\ number\ ranges.\n\ \ \ \[Concatenating\ lists\]:\ \ \ \n\ \ \ *\ \[AsserTcl\]:\ \ \ Supports\ quantifier\ commands\ to\ test\ whether\ an\ expressions\ holds\ universally\ or\ existentially\ over\ a\ data\ structure\ such\ as\ a\ list\ or\ array\ aggreggate\ data\ structure.\n\ \ \ \[list\ stripping\]:\ \ \ \n\ \ \ *\ \[Cartesian\ product\ of\ a\ list\ of\ lists\]:\ \ \ \n\ \ \ \[List\ trim\]:\ \ \ \n\ \ \ *\ \[Counting\ Elements\ in\ a\ List\]:\ \ \ \n\ \ \ \[lsplit\]:\ \ \ creates\ two\ lists\ from\ a\ single\ list\ and\ a\ test\ expression\ \n\n\ \ \ \[MakeRanges\]:\ \ \ Takes\ a\ list\ of\ numbers\ and\ makes\ them\ into\ a\ a\ list\ of\ number\ ranges.\n\n\ \ \ \[nested\ list\ join\]:\ \ \ \n\n\ \ \ \[permutations\]:\ \ \ \n\n\ \ \ \[Power\ set\ of\ a\ list\]:\ \ \ \n\n\ \ \ \[split\ and\ join\ for\ nested\ lists\]:\ \ \ \n\n\ \ \ \[Using\ expr\ on\ lists\]:\ \ \ \n\n\ \ \ \[Summing\ a\ list\]:\ \ \ \n\n\ \ \ \[Unique\ Element\ List\]:\ \ \ \n\n\ \ \ \[lolcat\]:\ \ \ Process\ a\ list\ into\ another\ list\ that\ contains\ more\ values\ than\ the\ original\ list.\n\n\n\n\ \ \ *\ \[Depth\ of\ a\ list\]:\ \ \ \n\ \ \ *\ \[diff\ in\ Tcl\]:\ \ \ longest\ common\ subsequence\n\ \ \ *\ \[ftp://ftp.tcl.tk/pub/tcl/mirror/ftp.procplace.com/sorted/packages-7.6/devel/keylprint.README%|%key\ list\ printing\ procedures\]:\ \ \ pretty\ prints\ Tclx's\ \[http://www.tcl.tk/man/tclx8.2/TclX.n.html%|%key\ lists\].\n\ \ \ \[AsserTcl\]:\ \ \ Supports\ quantifier\ commands\ to\ test\ whether\ an\ expressions\ holds\ universally\ or\ existentially\ over\ a\ data\ structure\ such\ as\ a\ list\ or\ array\ aggreggate\ data\ structure.\n\ \ \ *\ \[Complex\ data\ structures\]\ for\ \[struct\]:\ \ \ Named\ access\ to\ list\ positions.\n\ \ \ \[Cartesian\ product\ of\ a\ list\ of\ lists\]:\ \ \ \n\ \ \ *\ \[Decision\ trees\]:\ \ \ \n\ \ \ \[Counting\ Elements\ in\ a\ List\]:\ \ \ \n\ \ \ *\ \[keyed\ list\]:\ \ \ \n\ \ \ \[Depth\ of\ a\ list\]:\ \ \ \n\n\ \ \ \[diff\ in\ Tcl\]:\ \ \ longest\ common\ subsequence\n\n\ \ \ \[ftp://ftp.tcl.tk/pub/tcl/mirror/ftp.procplace.com/sorted/packages-7.6/devel/keylprint.README%|%key\ list\ printing\ procedures\]:\ \ \ pretty\ prints\ Tclx's\ \[http://www.tcl.tk/man/tclx8.2/TclX.n.html%|%key\ lists\].\n\n\ \ \ \[ldiff\]:\ \ \ Find\ the\ difference\ of\ two\ lists.\n\n\ \ \ \[lexpr\]:\ \ \ \n\n\ \ \ \[list\ level\]:\ \ \ \n\n\ \ \ \[ldiff\],\ by\ \[PL\]:\ \ \ Find\ the\ difference\ of\ two\ lists.\n\n\ \ \ \[plist\]:\ \ \ is\ for\ lists\ what\ `\[parray\]`\ is\ for\ arrays.\n\n\n\n\ \ \ *\ \[linked\ lists\]:\ \ \ \n\ \ \ *\ \[Chart\ of\ proposed\ list\ functionality\]:\ \ \ \n\ \ \ \[Binary\ trees\]:\ \ \ \n\ \ \ *\ \[internal\ organization\ of\ the\ list\ extension\]:\ \ \ \n\ \ \ \[Bit\ vectors\]:\ \ \ Can\ nicely\ be\ implemented\ with\ lists.\n\ \ \ *\ \[list\]:\ \ \ Contains\ (pointers\ to\ other\ Tcl\ specific\ list\ related\ commands.\n\ \ \ \[Complex\ data\ structures\]\ for\ \[struct\]:\ \ \ Named\ access\ to\ list\ positions.\n\n\ \ \ \[Decision\ trees\]:\ \ \ \n\n\ \ \ \[keyed\ list\]:\ \ \ \n\n\ \ \ \[linked\ lists\]:\ \ \ \n\n\ \ \ \[nxs\]:\ \ \ Nested\ heterogeneous\ data\ structures.\n\n\ \ \ \[set\ operations\ for\ Tcl\ lists\]:\ \ \ \n\n\ \ \ \[Stacks\ and\ queues\]:\ \ \ \n\n\ \ \ \[trees\ as\ nested\ lists\]:\ \ \ \n\n\ \ \ \[yet\ another\ stack\ package\]:\ \ \ \n\n\n\n\ \ \ *\ \[Showing\ sublists\]:\ \ \ In\ a\ listbox.\n\n\ \ \ \[Chart\ of\ existing\ list\ functionality\]:\ \ \ \n\n\ \ \ \[Chart\ of\ proposed\ list\ functionality\]:\ \ \ \n\[LV\]:\ Anyone\ have\ a\ URL\ for\ this\ ''posting''\ of\ forest.tcl\ ?\n\ \ \ \[internal\ organization\ of\ the\ list\ extension\]:\ \ \ \n\n\ \ \ \[list\]:\ \ \ Contains\ (pointers\ to\ other\ Tcl\ specific\ list\ related\ commands.\n\n\ \ \ \[Showing\ sublists\]:\ \ \ In\ a\ listbox.\n\n\n\n----\n\nOutline\ of\ the\ next\ steps\ to\ do:\n\n\ \ \ *\ Go\ through\ extensions\ listed\ above\ and\ collect\ all\ of\ their\ functionality\ in\ a\ table.\ Group\ equal\ and/or\ similar\ functionality\ together.\ \[Chart\ of\ existing\ list\ functionality\]\n\ \ \ *\ Define\ the\ functionality\ we\ want\ to\ have\ in\ the\ official\ extension.\ (Or\ shall\ we\ skip\ this\ in\ favor\ of\ a\ '''take\ all'''\ approach\ ?).\ --\ AK:\ No.\ After\ looking\ at\ the\ available\ functionality\ I\ believe\ that\ some\ parts\ may\ need\ a\ little\ pruning.\ \[Chart\ of\ proposed\ list\ functionality\].\n\ \ \ *\ Implement\ the\ functionality.\n\nAreas\ of\ discussion:\n\n\ \ \ *\ What\ functionality\ is\ provided,\ what\ do\ we\ want,\ what\ is\ missing,\ or\ superfluous\ ?\ LV\ already\ started\ a\ wishlist,\ see\ below.\n\ \ \ *\ \[Internal\ organization\ of\ the\ list\ extension\],\ commenting\ style,\ which\ namespace,\ ...\n\n----\n\n\[LV\]:\ \ Another\ useful\ thing\ would\ be\ a\ 'wishlist'\ (excuse\ the\ pun)\ of\nfunctionality\ requested.\ \ This\ would\ include\ things\ like\ (all\ of\ these\ have,\ in\nthe\ past,\ either\ been\ posted\ to\ the\ newsgroup\ or\ offered\ by\ a\ contributor\ to\nthe\ newsgroup\ -\ so\ if\ code\ is\ desired,\ the\ contacts\ listed\ in\n\[http://www.purl.org/net/tcl-faq/part5.html\]\ should\ be\ emailed.):\n\n\ \ \ \ *\ \[lassign\]\ -\ Assign\ \[elements\]\ of\ list\ to\ the\ given\ variables.\ --\ AK:\ Already\ provided\ by\ some\ extensions.\ RS:\ ...\ or\ \[foreach\].\ \[DKF\]:\ In\ the\ core\ in\ 8.5.\n\ \ \ \ *\ linear\ sort\ on\ list\ of\ lists\ -\ Alphanumeric\ comparison\ for\ linear\ sort\ of\ lists.\ --\ AK:\ '''???'''\ \[Lars\ H\]:\ Does\ this\ mean\ lexicographic\ sort?\ To\ compare\ elements\ L1\ and\ L2,\ first\ compare\ their\ first\ elements\ \[\[lindex\ \$L1\ 0\]\]\ and\ \[\[lindex\ \$L2\ 0\]\].\ If\ these\ are\ equal,\ compare\ the\ second\ elements,\ and\ so\ on.\n\ \ \ \ *\ Linked\ list\ support.\ I\ (AK)\ had\ a\ problem\ here,\ but\ Larry\ solved\ it\ for\ me.\ Meant\ is\ stack/queue-like\ access\ to\ the\ list.\ Some\ extensions\ already\ provide\ this\ functionality:\ \[yet\ another\ stack\ package\].\n\ \ \ \ *\ Remove\ empty\ elements\ from\ list.\ --\ '''NEW'''.\ Added\ to\ proposed\ list\ of\ functions.\n\ \ \ \ *\ Given\ one\ list,\ create\ a\ new\ list\ consisting\ only\ of\ the\ unique\ elements.\ --\ AK:\ Provided\ by\ some\ extensions.\ \[Lars\ H\]:\ How\ is\ this\ different\ from\ \[\[lsort\ -unique\]\]?\n\ \ \ \ *\ Even\ better\ -\ provide\ list\ sorting\ capability\ equal\ or\ greater\ than\ Unix\ sort-\ --\ '''NEW'''.\ AK:\ This\ will\ be\ difficult.\n\ \ \ \ *\ tclX\ code\ to\ return\ subsets\ of\ lists,\ based\ on\ patterns.\ --\ AK:\ Provided\ by\ some\ extensions,\ but\ most\ not\ as\ complete\ as\ \[TclX\].\ (\[DKF\]:\ This\ can\ be\ done\ with\ \[lsearch\]\;\ '''\[\[lsearch\ -all\ -inline\ -glob\ \$theList\ \$theGlobPattern\]\]''')\n\ \ \ \ *\ parse\ a\ list\ into\ variables\ similar\ to\ the\ way\ a\ command\ line\ is\ parsed.\ --\ AK:\ getopt-like,\ place\ in\ that\ extension.\n\ \ \ \ *\ Compare\ two\ lists\ for\ equality.\ --\ '''NEW'''.\ AK:\ Looks\ so\ innocent.\ What\ is\ equality\ ?\ With\ order\ ?\ Without\ ?\ What\ about\ duplicates\ ?\ These\ are\ several\ functions.\ Not\ yet\ in\ the\ proposed\ list.\n\ \ \ \ *\ A\ number\ of\ people\ have\ written\ a\ variety\ of\ 'database\ query\ results'\ to\ 'list'\ type\ interfaces.\ \ I\ wonder\ if\ something\ generic\ could\ be\ created.\n\ \ \ \ *\ Transpose\ elements\ within\ list\ of\ lists\ --\ AK:\ Primitives\ for\ that\ already\ provided\ by\ some\ extensions.\n\ \ \ \ *\ \[ulis\]:\ ldelete\ list-name\ ?index...?,\ remove\ the\ items\ in\ place.\n\ \ \ \ *\ \[ulis\]:\ leval\ \$list,\ eval\ without\ concat.\ \ \[DKF\]:\ In\ Tcl\ 8.5,\ just\ use\ '''\[\[\{*\}\$list\]\]'''\ which\ is\ now\ part\ of\ the\ core\ language\ syntax.\n\n----\n\n\[AK\]:\ \ I\ have\ to\ admit\ that\ I\ currently\ see\ ''keyed\ lists''\ as\ something\ to\neither\ add\ later,\ or\ to\ place\ them\ into\ a\ separate\ extension.\n\n\[AK\]:\ \ I\ would\ also\ vote\ to\ definitely\ place\ DB\ interfaces\ into\ their\ own\nextension.\n\nDL:\ \ also\ look\ at\ list\ utilities\ in\ the\ opt\ package\ of\ tcl\ 8.\[\[01\]\]\ (mostly\ntclX\ 'compatible'\ though)\n\n----\n\n\[Nat\ Pryce\]:\ \ I\ have\ implemented\ ''map'',\ ''fold''\ and\ ''zip''\ functions\ in\ C\nand\ ''lambda''\ functions\ in\ Tcl,\ but\ never\ released\ them.\ \ Anyone\ who\ is\nworking\ on\ a\ list\ extension\ package\ is\ welcome\ to\ the\ code.\n\n----\n\n\[Larry\ Virden\]:\ the\ following\ pages\ have\ recently\ appeared\ on\ the\ Wiki:\n\[Shuffle\ a\ list\],\ \[Striding\ a\ list\],\ \[Summing\ a\ list\]\ -\ \[Cartesian\ product\ of\ a\nlist\ of\ lists\]\ \[Recursive\ list\ searching\]\n\n----\n\nHere's\ some\ little\ helpers\ just\ for\ taking\ out:\n\n'''List\ element''':\n\n======\nproc\ lel\ \{L\ element\}\ \{expr\ \{\[lsearch\ \$L\ \$element\]>=0\}\}\n======\n\n======\npackage\ require\ Tcl\ 8.5\nproc\ lel\ \{L\ element\}\ \{\ expr\ \{\ \$element\ in\ \$L\ \}\ \}\n======\n\nThough\ if\ you\ have\ Tcl8.5\ you\ should\ write\ `if\ \{\$elt\ in\ \$list\}\ ...`\ rather\ than\ `if\ \{\[\[lel\ \$list\ \$elt\]\]\}\ ...`.\n\n'''Add\ an\ element\ to\ a\ list'''\ only\ if\ not\ present\ yet:\n\n======\nproc\ ladd\ \{_L\ args\}\ \{\n\ \ \ \ upvar\ \$_L\ L\n\ \ \ \ if\ \{!\[info\ exists\ L\]\}\ \{set\ L\ \{\}\}\n\ \ \ \ foreach\ i\ \$args\ \{if\ \{!\[lel\ \$L\ \$i\]\}\ \{lappend\ L\ \$i\}\}\n\}\n======\n\n'''Random\ element'''\ selected\ from\ a\ list:\n\n======\nproc\ lrandom\ L\ \{lindex\ \$L\ \[expr\ \{int(rand()*\[llength\ \$L\])\}\]\}\n======\n\n'''Random\ element'''\ drawn\ (and\ removed)\ from\ a\ list:\n\n======\nproc\ ldraw\ \{_L\}\ \{\n\ \ \ \ upvar\ 1\ \$_L\ L\n\ \ \ \ set\ pos\ \[expr\ \{int(rand()\ *\ \[llength\ \$L\])\}\]\n\ \ \ \ set\ res\ \[lindex\ \$L\ \$pos\]\n\ \ \ \ set\ L\ \[lreplace\ \$L\ \$pos\ \$pos\]\n\ \ \ \ set\ res\n\}\n======\n\n'''Remove\ elements\ from\ a\ list'''\ by\ value:\n\n======\nproc\ lremove\ \{_L\ args\}\ \{\n\ \ \ upvar\ \$_L\ L\n\ \ \ foreach\ i\ \$args\ \{\n\ \ \ \ \ \ \ set\ pos\ \[lsearch\ \$L\ \$i\]\ \;#\ might\ be\ -1\ if\ not\ found...\n\ \ \ \ \ \ \ set\ L\ \[lreplace\ \$L\ \$pos\ \$pos\]\ \;#\ ...\ but\ that's\ fine\n\ \ \ \}\n\}\n======\n\n'''\[lreverse%|%Reverse\]\ the\ order\ of\ a\ list''':\n\nSince\ 8.5,\ `\[lreverse\]`\ is\ a\ \[Tcl\ Commands%|%built-in\]\ Tcl\ command.\n\n======\nproc\ lreverse\ L\ \{\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ set\ i\ \[llength\ \$L\]\n\ \ \ \ #while\ \{\[incr\ i\ -1\]>=0\}\ \{lappend\ res\ \[lindex\ \$L\ \$i\]\}\n\ \ \ \ while\ \{\$i\}\ \{lappend\ res\ \[lindex\ \$L\ \[incr\ i\ -1\]\]\}\ \;#\ rmax\n\ \ \ \ set\ res\n\}\ \;#\ RS,\ tuned\ 10%\ faster\ by\ \[rmax\]\n======\n\nHere's\ a\ simpler\ way\ to\ do\ it.\n\n======\nproc\ lreverse2\ l\ \{\n\ \ \ \ set\ ret\ \{\}\n\ \ \ \ foreach\ i\ \$l\ \{\n\ \ \ \ \ \ \ \ set\ ret\ \[linsert\ \$ret\ 0\ \$i\]\n\ \ \ \ \}\n\ \ \ \ return\ \$ret\n\}\ #EAS\n======\n\n\[RS\]:\ \ Note\ however\ that\ the\ `\[linsert\]`\ requires\ copying\ the\ whole\ sublist\ N\ntimes,\ while,\ the\ `\[lappend\]`\ copies\ each\ element\ exactly\ once.\n\n\[KPV\]:\ \ Here\ are\ three\ more\ ways\ of\ reversing\ a\ list\ that\ utilize\ \[lset\]\ to\nswap\ pairs\ of\ elements\ in\ place:\n\n======\nproc\ lreverse3\ \{l\}\ \{\n\ \ \ \ set\ start\ -1\n\ \ \ \ set\ end\ \[llength\ \$l\]\n\n\ \ \ \ while\ \{\[incr\ start\]\ <\ \[incr\ end\ -1\]\}\ \{\n\ \ \ \ \ \ \ \ set\ tmp\ \[lindex\ \$l\ \$start\]\n\ \ \ \ \ \ \ \ lset\ l\ \$start\ \[lindex\ \$l\ \$end\]\n\ \ \ \ \ \ \ \ lset\ l\ \$end\ \$tmp\n\ \ \ \ \}\n\ \ \ \ return\ \$l\n\}\n======\n\nFor\ long\ lists\ you\ can\ squeeze\ out\ a\ bit\ more\ performance\ with\ the\ help\ of\n`\[foreach\]`:\n\n======\nproc\ lreverse4\ \{l\}\ \{\n\ \ \ \ set\ start\ -1\n\ \ \ \ set\ end\ \[llength\ \$l\]\n\ \ \ \ \n\ \ \ \ foreach\ tmp\ \$l\ \{\n\ \ \ \ \ \ \ \ if\ \{\[incr\ start\]\ >=\ \[incr\ end\ -1\]\}\ break\n\ \ \ \ \ \ \ \ lset\ l\ \$start\ \[lindex\ \$l\ \$end\]\n\ \ \ \ \ \ \ \ lset\ l\ \$end\ \$tmp\n\ \ \ \ \}\n\ \ \ \ return\ \$l\n\}\n======\n\nHere's\ a\ very\ simple\ version\ —\ faster\ than\ `lreverse4`\ but\ alas\ not\ the\nfastest:\n\n======\nproc\ lreverse5\ \{l\}\ \{\n\ \ \ \ set\ end\ \[llength\ \$l\]\n\ \ \ \ foreach\ tmp\ \$l\ \{\n\ \ \ \ \ \ \ \ lset\ l\ \[incr\ end\ -1\]\ \$tmp\n\ \ \ \ \}\n\ \ \ \ return\ \$l\n\}\n======\n\n\[Lars\ H\]:\ \ This\ is\ not\ fast,\ but\ it\ avoids\ index\ arithmetic.\ \ The\ idea\ can\ be\nnice\ in\ cases\ where\ you\ want\ to\ process\ the\ list\ elements\ while\ reversing\ their\norder.\n\n======\nproc\ lreverse6\ \{l\}\ \{\n\ \ \ \ set\ stack\ \{\}\n\ \ \ \ foreach\ item\ \$l\ \{set\ stack\ \[list\ \$stack\ \$item\]\}\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ while\ \{\[llength\ \$stack\]\}\ \{\n\ \ \ \ \ \ \ foreach\ \{stack\ item\}\ \$stack\ break\n\ \ \ \ \ \ \ lappend\ res\ \$item\n\ \ \ \ \}\n\ \ \ \ return\ \$res\n\}\n======\n\n\n'''Sort\ a\ list\ on\ multiple\ indices''':\n\n======\nproc\ multisort\ \{indices\ L\ args\}\ \{\n\ \ \ \ set\ cmd\ \"list\ \$L\"\n\ \ \ \ foreach\ i\ \[lreverse\ \$indices\]\ \{\n\ \ \ \ \ \ \ set\ cmd\ \"lsort\ \$args\ -index\ \$i\ \\\[\$cmd\\\]\"\n\ \ \ \ \}\n\ \ \ \ eval\ \$cmd\n\}\ \;#\ RS\n======\n\n======none\n%\ multisort\ \{2\ 0\ 1\}\ \ \{\{abe\ zyx\ 25\}\ \{john\ smith\ 14\}\ \{harold\ brown\ 99\}\ \{mary\ jones\ 32\}\}\n\{john\ smith\ 14\}\ \{abe\ zyx\ 25\}\ \{mary\ jones\ 32\}\ \{harold\ brown\ 99\}\n%\ multisort\ \{0\ 2\ 1\}\ \ \{\{abe\ zyx\ 25\}\ \{john\ smith\ 14\}\ \{harold\ brown\ 99\}\ \{mary\ jones\ 32\}\}\ -decreasing\n\{mary\ jones\ 32\}\ \{john\ smith\ 14\}\ \{harold\ brown\ 99\}\ \{abe\ zyx\ 25\}\n======\n\nsee\ also:\ \[Custom\ sorting\]\n\n----\n\n'''Permute\ a\ list''':\ \ returns\ a\ list\ of\ the\ possible\ orderings\ of\ the\ input\nlist,\ e.g.\ `lpermute\ \{a\ b\ c\}\ =>\ \{\{a\ b\ c\}\ \{a\ c\ b\}\ \{b\ a\ c\}\ \{b\ c\ a\}\ \{c\ a\ b\}\ \{c\ b\na\}\}`.\ Be\ aware\ that\ the\ output\ length\ grows\ factorially,\ so\ a\ 7-element\ input\nproduces\ over\ 5000\ permutations...\n\n======\nproc\ lpermute\ L\ \{\n\ \ \ \ if\ \{\[llength\ \$L\]\ <\ 2\}\ \{\n\ \ \ \ \ \ \ \ set\ res\ \$L\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ pos\ 0\n\ \ \ \ \ \ \ \ foreach\ i\ \$L\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rest\ \[lreplace\ \$L\ \$pos\ \$pos\]\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ pos\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ j\ \[lpermute\ \$rest\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ res\ \[concat\ \[list\ \$i\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ res\n\}\ \;#\ RS\n======\n\n''Find\ the\ list\ element\ numerically\ closest\ to\ a\ given\ value'''\n\n\[\[F\]or\ a\ given\ value,\ find\ one\ element\ from\ a\ given\ list\ with\ minimal\ absolute\ndifference\ \[\[...\]\n\n======\nproc\ closest\ \{value\ list\}\ \{\n\ \ \ \ set\ minElement\ \[lindex\ \$list\ 0\]\n\ \ \ \ set\ minDist\ \[expr\ \{abs(\$value-\$minElement)\}\]\n\ \ \ \ foreach\ i\ \[lrange\ \$list\ 1\ end\]\ \{\n\ \ \ \ \ \ \ if\ \{abs(\$value-\$i)\ <\ \$minDist\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ set\ minDist\ \[expr\ \{abs(\$value-\$i)\}\]\n\ \ \ \ \ \ \ \ \ \ \ set\ minElement\ \$i\n\ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ minElement\n\}\nIn\ borderline\ cases,\ it\ picks\ the\ first\ hit,\ though:\n%\ closest\ \ 2.5\ \{1\ 2\ 3\ 4\ 5\}\n2\n======\n\n----\n\n'''Compact\ an\ integer\ list:'''\ merge\ consecutive\ numbers,\ if\ more\ than\ two,\ninto\ a\ dash-separated\ range\ (an\ extra\ element\ is\ appended\ to\ the\ list\ to\ncollect\ the\ final\ buffer):\n\n======\nproc\ rangify\ list\ \{\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ set\ buf\ \{\}\n\ \ \ \ foreach\ i\ \[lappend\ list\ \{\}\]\ \{\n\ \ \ \ \ \ \ \ if\ \{\$buf\ eq\ \{\}\ ||\ \$i\ ==\ \[lindex\ \$buf\ end\]\ +\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ buf\ \$i\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$buf\]\ >\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ buf\ \[lindex\ \$buf\ 0\]-\[lindex\ \$buf\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ res\ \$buf\n\ \ \ \ \ \ \ \ \ \ \ \ set\ buf\ \$i\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ join\ \$res\n\}\ \;#RS\n======\n\n======none\n%\ rangify\ \{1\ 2\ 3\ 5\ 6\ 7\ 9\ 10\ 12\ 13\ 14\ 17\ 18\ 19\}\n1-3\ 5-7\ 9\ 10\ 12-14\ 17-19\n======\n\nHere's\ an\ alternative\ remake\ of\ October\ 2005,\ with\ an\ expander,\ too:\n\n======\nproc\ compress\ list\ \{\ \n\ \ \ \ set\ res\ \[lindex\ \$list\ 0\]\ \n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <\ \[llength\ \$list\]\ -\ 1\}\ \{incr\ i\}\ \{\ \n\ \ \ \ \ \ \ set\ it\ \[lindex\ \$list\ \$i\]\ \n\ \ \ \ \ \ \ if\ \{\$it\ ==\ \[lindex\ \$list\ \[expr\ \{\$i-1\}\]\]\ +\ 1\ \n\ \ \ \ \ \ \ \ \ \ \ &&\ \$it\ ==\ \[lindex\ \$list\ \[expr\ \{\$i+1\}\]\]\ -\ 1\}\ \{\ \n\n\ \ \ \ \ \ \ \ \ \ \ lappend\ res\ -\ \n\ \ \ \ \ \ \ \}\ else\ \{lappend\ res\ \$it\}\ \n\ \ \ \}\ \n\ \ \ lappend\ res\ \[lindex\ \$list\ end\]\ \n\ \ \ regsub\ -all\ --\ \{\ -\ (-\ )*\}\ \$res\ -\ \n\}\n\n#----\ For\ the\ way\ back:\nproc\ expand\ clist\ \{\ \n\ \ \ \ set\ res\ \{\}\ \n\ \ \ \ foreach\ part\ \$clist\ \{\ \n\ \ \ \ \ \ \ \ if\ \[regexp\ \{(\[0-9-\]*\[0-9\])-(.+)\}\ \$part\ ->\ from\ to\]\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ while\ \{\$from\ <=\ \$to\}\ \{lappend\ res\ \$from\;\ incr\ from\}\ \n\ \ \ \ \ \ \ \ \}\ else\ \{lappend\ res\ \$part\}\ \n\ \ \ \ \}\ \n\ \ \ \ set\ res\ \n\}\;#\ RS\n======\n\n----\n\n'''List\ constructor:'''\ After\ the\ advent\ of\ multi-index\ \[lindex\]\ and\ \[lset\],\nnested\ lists\ can\ conveniently\ be\ used\ e.g.\ for\ matrixes,\ but\ all\ list\ elements\nmust\ be\ present\ for\ them\ to\ work.\ Here's\ a\ nestable\ constructor\ that\ fills\ a\nlist\ with\ the\ specified\ initial\ value:\n\n======\nproc\ lrepeat\ \{value\ number\}\ \{\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i<\$number\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ lappend\ res\ \$value\n\ \ \ \ \}\n\ \ \ \ set\ res\n\}\ \;#\ RS\n%\ lrepeat\ foo\ 5\nfoo\ foo\ foo\ foo\ foo\n%\ lrepeat\ \[lrepeat\ 0\ 5\]\ 5\n\{0\ 0\ 0\ 0\ 0\}\ \{0\ 0\ 0\ 0\ 0\}\ \{0\ 0\ 0\ 0\ 0\}\ \{0\ 0\ 0\ 0\ 0\}\ \{0\ 0\ 0\ 0\ 0\}\n======\n\nThe\ second\ edition\ saves\ you\ the\ nesting,\ accepts\ indices\ in\ a\ list\ or\nseparately,\ just\ like\ lset\ or\ lindex:\n\n======\nproc\ lrepeat\ \{value\ args\}\ \{\n\ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 1\}\ \{set\ args\ \[lindex\ \$args\ 0\]\}\n\ \ \ \ foreach\ number\ \$args\ \{\n\ \ \ \ \ \ \ incr\ number\ 0\ \;#\ force\ integer\ (1)\n\ \ \ \ \ \ \ set\ buf\ \{\}\n\ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$number\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ lappend\ buf\ \$value\n\ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ set\ value\ \$buf\n\ \ \ \ \}\n\ \ \ \ set\ buf\n\}\n%\ lrepeat\ \ 0\ 3\ 4\n\{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\n%\ lrepeat\ \ 0\ \{3\ 4\}\n\{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\n%\ lrepeat\ \ 0\ \{3\ 4\ 5\}\n\{\{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\}\ \{\{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\}\ \{\{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\}\ \{\{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\}\ \{\{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\}\n======\n\n(1):\ See\ \[Stress\ testing\]\ for\ why\ this\ makes\ the\ code\ safer.\n\n\[DKF\]:\ Tcl\ 8.5a0\ has\ a\ variation\ on\ this\ which\ behaves\ like\ this:\n\n======\nproc\ lrepeat\ \{count\ value\ args\}\ \{\n\ \ \ \ set\ values\ \[linsert\ \$args\ 0\ \$value\]\n\ \ \ \ set\ result\ \{\}\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$count\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ eval\ \[list\ lappend\ result\]\ \$values\n\ \ \ \ \}\n\ \ \ \ return\ \$result\n\}\n======\n\nAnd\ now,\ because\ I\ can't\ resist\ it,\ here's\ an\ even\ hackier\ way\ to\ do\ it.\ \ :^D\n\n======\nproc\ lrepeat\ \{count\ args\}\ \{\n\ \ \ \ set\ result\ \{\}\n\ \ \ \ set\ cmd\ \[list\ eval\ \[list\ lappend\ result\]\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$count\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ lappend\ cmd\ \$args\n\ \ \ \ \}\n\ \ \ \ eval\ \$cmd\n\}\n======\n\n\[AMG\]:\ This\ second\ version\ is\ the\ more\ efficient\ of\ the\ two.\ \ It\ is\ also\ more\ correct\ in\ that\ it\ allows\ \[\[\[lrepeat\]\]\]\ to\ take\ only\ one\ argument\ (the\ count),\ in\ which\ case\ it\ returns\ empty\ string.\ \ Though\ to\ be\ pedantic,\ both\ are\ technically\ incorrect\ for\ Tcl\ 8.5a0\ which\ predates\ TIP\ 323\ \[http://tip.tcl.tk/323\]\;\ back\ then,\ \[\[lrepeat\]\]\ arbitrarily\ rejected\ \$count\ =\ 0.\n\n\[FW\]:\ Here's\ a\ most\ minimalist\ way\ (and\ of\ course\ the\ less\ efficient).\n\n======\nproc\ lrepeat\ \{count\ args\}\ \{string\ repeat\ \"\$args\ \"\ \$count\}\n======\n\n\[AMG\]:\ \[DKF\]'s\ \"efficient\"\ version\ does\ far\ more\ work\ than\ it\ has\ to.\ \ Here's\ a\ significantly\ faster\ approach:\n\n======\nproc\ lrepeat\ \{count\ args\}\ \{\n\ \ \ \ set\ cmd\ \[list\ concat\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$count\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ lappend\ cmd\ \$args\n\ \ \ \ \}\n\ \ \ \ eval\ \$cmd\n\}\n======\n\nAnd\ another\ version\ with\ a\ slightly\ faster\ loop:\n\n======\nproc\ lrepeat\ \{count\ args\}\ \{\n\ \ \ \ set\ cmd\ \[list\ concat\]\n\ \ \ \ incr\ count\n\ \ \ \ while\ \{\[incr\ count\ -1\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ cmd\ \$args\n\ \ \ \ \}\n\ \ \ \ eval\ \$cmd\n\}\n======\n\nTiming:\n\n======\n%\ info\ patchlevel\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \;#\ 8.6.1\n%\ time\ \{dkf_1\ \ \ 123\ x\ y\ z\}\ 10000\ \ \;#\ 773.3324\ microseconds\ per\ iteration\n%\ time\ \{dkf_2\ \ \ 123\ x\ y\ z\}\ 10000\ \ \;#\ 108.0783\ microseconds\ per\ iteration\n%\ time\ \{amg_1\ \ \ 123\ x\ y\ z\}\ 10000\ \ \;#\ \ 27.1447\ microseconds\ per\ iteration\n%\ time\ \{amg_2\ \ \ 123\ x\ y\ z\}\ 10000\ \ \;#\ \ 21.9983\ microseconds\ per\ iteration\n%\ time\ \{lrepeat\ 123\ x\ y\ z\}\ 10000\ \ \;#\ \ \ 3.5693\ microseconds\ per\ iteration\n======\n\nAnd\ for\ a\ laugh,\ here's\ the\ time\ for\ \[FW\]'s\ less\ efficient\ approach:\n\n======\n%\ time\ \{fw_1\ \ \ \ 123\ x\ y\ z\}\ 10000\ \ \;#\ \ \ 2.4697\ microseconds\ per\ iteration\n======\n\nYup.\ \ It's\ faster\ than\ the\ native\ \[\[lrepeat\]\]!\ \ But\ the\ return\ value\ is\ subtly\ different.\ \ Let's\ make\ it\ fair:\n\n======\n%\ proc\ fw_2\ \{count\ args\}\ \{linsert\ \[string\ repeat\ \"\$args\ \"\ \$count\]\ 0\}\n%\ time\ \{fw_2\ \ \ \ 123\ x\ y\ z\}\ 10000\ \ \;#\ \ 60.4778\ microseconds\ per\ iteration\n======\n\nThis\ version\ forces\ its\ result\ to\ be\ a\ pure\ list.\ \ And\ wow,\ despite\ being\ \"less\ efficient\",\ \[FW\]'s\ dalliance\ with\ strings\ is\ still\ faster\ than\ any\ of\ the\ list\ manipulation\ approaches\ that\ had\ preceded\ it.\ \ That's\ quite\ impressive.\ \ I\ believe\ the\ reason\ is\ that\ it\ avoids\ \[\[\[eval\]\]\]\ and\ all\ Tcl-based\ looping.\ \ It's\ just\ two\ commands,\ and\ almost\ no\ work\ is\ done\ in\ \[TEBC\].\n\n----\n'''List\ equality\ test'''\ independent\ of\ whitespace\ outside\ of\ elements:\ Taken\ from\ \[A\ little\ XML\ parser\]\ where\ you\ can\ find\ other\ things\ to\ do\ with\ lists\n\n======\nproc\ lequal\ \{a\ b\}\ \{\n\ \ \ \ if\ \{\[llength\ \$a\]\ !=\ \[llength\ \$b\]\}\ \{return\ 0\}\n\ \ \ \ if\ \{\[lindex\ \$a\ 0\]\ ==\ \$a\}\ \{return\ \[string\ equal\ \$a\ \$b\]\}\n\ \ \ \ foreach\ i\ \$a\ j\ \$b\ \{if\ \{!\[lequal\ \$i\ \$j\]\}\ \{return\ 0\}\}\n\ \ \ \ return\ 1\n\}\ \;#\ RS\n======\n\n\[HaO\]\ 2014-09-16:\ \[aspect\]\ proposed\ on\ the\ chat:\n======tcl\n\[list\ \{*\}\$l1\]\ eq\ \[list\ \{*\}\$l2\]\n======\n\n'''Check\ if\ combination\ of\ list\ elements\ is\ valid'''\ against\ a\ list\ of\ lists,\n\n\[JM\]\ 2004-01-04:\ \ this\ code\ relies\ on\ 'lequal'\n\n======\nset\ thisCase\ \[list\ a\ c\ b\]\n\nset\ lstValid\ \{\n\ \ \ \ \{a\ b\ c\}\n\ \ \ \ \{a\ a\ c\}\n\ \ \ \ \{a\ b\ b\}\n\ \ \ \ \{a\ a\ a\}\n\}\n======\n\n======\nproc\ chkValidCombination\ \{lstValid\ thisCase\}\ \{\n\ \ \ \ set\ valid\ 0\n\ \ \ \ foreach\ validCase\ \$lstValid\ \{\n\ \ \ \ \ \ \ \ set\ equal\ \[lequal\ \$validCase\ \$thisCase\]\n\ \ \ \ \ \ \ \ if\ \{\$equal\}\ \{set\ valid\ 1\}\n\ \ \ \ \}\n\n\ \ \ \ return\ \$valid\n\}\n\nputs\ \[chkValidCombination\ \$lstValid\ \$thisCase\]\n======\n\n----\n\n'''Keylist\ access:'''\ Data\ arranged\ as\ alternating\ ''key\ value''...\ can\ be\nsearched\ like\ this,\ where\ non-existing\ keys\ just\ return\ an\ empty\ list:\n\n======\nproc\ keyget\ \{list\ key\}\ \{\n\ \ \ \ foreach\ \{lkey\ value\}\ \$list\ \{\n\ \ \ \ \ \ \ \ if\ \[string\ equal\ \$lkey\ \$key\]\ \{return\ \$value\}\n\ \ \ \ \}\n\}\ \;#\ RS\n%\ keyget\ \{fnm\ John\ lnm\ Brown\ phone\ (123)456-7890\ email\ [email protected]\}\ phone\n(123)456-7890\n%\ keyget\ \{fnm\ John\ lnm\ Brown\ phone\ (123)456-7890\ email\ [email protected]\}\ fax\n======\n\n----\n\n'''Insert\ element\ into\ sorted\ list'''\ at\ suitable\ position:\n\n======\nproc\ linsertsorted\ \{list\ newElement\}\ \{\n\ \ \ \ set\ pos\ 0\n\ \ \ \ foreach\ element\ \$list\ \{\n\ \ \ \ \ \ \ \ if\ \{\$element\ >\ \$newElement\}\ break\n\ \ \ \ \ \ \ \ incr\ pos\n\ \ \ \ \}\n\ \ \ \ linsert\ \$list\ \$pos\ \$newElement\n\}\ \;#\ RS\ --\ testing:\n======\n======none\n%\ linsertsorted\ \{a\ b\ c\ d\ e\}\ f\na\ b\ c\ d\ e\ f\n%\ linsertsorted\ \{a\ b\ c\ d\ e\}\ 0\n0\ a\ b\ c\ d\ e\n%\ linsertsorted\ \{a\ b\ c\ d\ e\}\ aa\na\ aa\ b\ c\ d\ e\n======\n\n\[DKF\]\ notes\ that\ this\ is\ the\ most\ efficient\ way\ to\ maintain\ a\ sorted\ list\ of\nthings\ with\ occasional\ insertions\ of\ elements.\ \ The\ alternative\ -\ append\ and\nfull\ resort\ -\ is\ much\ more\ costly\ as\ the\ list\ size\ increases.\n\n\[jcw\]\ 2004-10-04:\ \ Let\ me\ split\ hairs\ here.\ \ What\ you\ end\ up\ with\ is\ \"insertion\nsort\",\ not\ the\ most\ efficient\ sort\ algorithm\ in\ the\ world.\ \ For\ single,\nincidental\ inserts:\ yes,\ good\ approach.\ \ But\ if\ the\ insertions\ come\ in\ bursts,\nit's\ not\ optimal.\ \ One\ could\ collect\ insertions,\ and\ resort\ lazily\ on\ first\naccess.\ \ Implementation\ left\ as\ exercise\ for\ the\ reader\ (heh!).\n\n\[AF\]:\ \ here\ is\ my\ implementation\ of\ a\ BINARY\ insertion\ sort:\n\n======\nproc\ BinaryInsert\ \{list\ pattern\}\ \{\n\ \ \ \ set\ lo\ -1\n\ \ \ \ set\ hi\ \[llength\ \$list\]\n\ \ \ \ set\ test\ \[expr\ \{\$hi\ /\ 2\}\]\n\ \ \ \ while\ \{\$lo\ !=\ \$test\}\ \{\n\ \ \ \ \ \ \ \ set\ res\ \[string\ compare\ -nocase\ \[lindex\ \$list\ \$test\]\ \$pattern\]\n\ \ \ \ \ \ \ \ if\ \{\$res\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ lo\ \$test\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$res\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ hi\ \$test\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[linsert\ \$list\ \$test\ \$pattern\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ test\ \[expr\ \{(\$hi\ +\ \$lo)\ /\ 2\}\]\n\ \ \ \ \}\n\ \ \ \ return\ \[linsert\ \$list\ \$hi\ \$pattern\]\n\}\n======\n\n----\n\n'''Swap\ a\ paired\ list''':\ e.g.\ dictionaries,\ string\ maps,\ x/y\ coordinates...\n\n======\nproc\ lswap\ list\ \{\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ foreach\ \{a\ b\}\ \$list\ \{lappend\ res\ \$b\ \$a\}\n\ \ \ \ set\ res\n\}\ \;#\ RS\n%\ lswap\ \{a\ b\ c\ d\ e\ f\ g\ h\}\nb\ a\ d\ c\ f\ e\ h\ g\n======\n\n----\n\n'''List\ intersection:'''\ For\ a\ number\ of\ lists,\ return\ only\ those\ elements\ that\nare\ present\ in\ all\ lists:\n\n======\nproc\ intersect\ args\ \{\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ \ \ \ \ foreach\ element\ \[lindex\ \$args\ 0\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ list\ \[lrange\ \$args\ 1\ end\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lsearch\ -exact\ \$list\ \$element\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 0\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$found\}\ \{lappend\ res\ \$element\}\n\ \ \ \ \ \}\n\ \ \ \ \ set\ res\n\}\ \;#\ RS\n======\n\[kpv\]\ 2018-10-24:\ here's\ a\ one-liner\ using\ \[lmap\]\ for\ intersecting\ two\ lists:\n======\nset\ intersect\ \[lmap\ a\ \$alist\ \{if\ \{\$a\ in\ \$blist\}\ \{set\ a\}\ else\ continue\}\]\n======\n\[RS\]\ 2015-05-13:\ a\ simpler\ take\ for\ two\ lists,\ using\ the\ \[in\]\ operator:\n======\n\n\}\n======\n\n\[RKzn\]\ 2016-09-28:\ the\ previous\ proc\ works\ provided\ the\ first\ list\ does\ not\ have\ duplicate\ elements.\ Otherwise\ all\ elements\ from\ the\ first\ list\ that\ match\ at\ least\ one\ element\ from\ the\ second\ list\ will\ be\ included\ in\ the\ result:\n\n======\ntcl>\ lintersect\ \{a\ b\}\ \{a\ c\}\na\ntcl>\ lintersect\ \{a\ a\ b\}\ \{a\ c\}\na\ a\n======\n\nBy\ the\ way,\ lists\ without\ duplicates\ (or\ ignoring\ the\ ones\ that\ may\ exist)\ can\ be\ seen\ as\ sets.\ For\ those,\ there\ are\ implementations\ for\ intersection\ in\ \[tcllib\]:\ '::\[struct::set\]\ intersect'\ and\ '::struct::set\ intersect3'\n\n\n\ \ \ inList2:\ \ \ Name\ of\ the\ list\ in\ which\ to\ put\ list2\ only\ elements\n\n\ \ \ inBoth:\ \ \ Name\ of\ the\ list\ in\ which\ to\ put\ elements\ in\ list1\ &\ list2\n\n======\nproc\ intersect3\ \{list1\ list2\ inList1\ inList2\ inBoth\}\ \{\n\ \ \ \ upvar\ \$inList1\ in1\n\ \ \ \ upvar\ \$inList2\ in2\n\ \ \ \ upvar\ \$inBoth\ \ inB\n\n\ \ \ \ set\ in1\ \[list\]\n\ \ \ \ set\ in2\ \[list\]\n\ \ \ \ set\ inB\ \[list\]\n\n\ \ \ \ set\ list1\ \[lsort\ \$list1\]\n\ \ \ \ set\ list2\ \[lsort\ \$list2\]\n\n\ \ \ \ #\ Shortcut\ for\ identical\ lists\ is\ faster\n\ \ \ \ if\ \{\ \$list1\ ==\ \$list2\ \}\ \{\ \ \ \n\ \ \ \ \ \ \ \ set\ inB\ \$list1\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ i\ 0\n\ \ \ \ \ \ \ \ foreach\ element\ \$list1\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[set\ p\ \[lsearch\ \[lrange\ \$list2\ \$i\ end\]\ \$element\]\]\ ==\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ in1\ \$element\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ \$p\ >\ 0\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ e\ \[expr\ \{\$i\ +\ \$p\ -1\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ entry\ \[lrange\ \$list2\ \$i\ \$e\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ in2\ \$entry\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ i\ \$p\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ inB\ \$element\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ foreach\ entry\ \[lrange\ \$list2\ \$i\ end\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ in2\ \$entry\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\ \;#\ David\ Easton\n======\n\n----\n\n'''Prepend\ elements\ to\ a\ list'''\ (add\ in\ front):\n\n======\nproc\ lprepend\ \{var\ args\}\ \{\n\ \ \ \ upvar\ 1\ \$var\ v\n\ \ \ \ set\ v\ \[eval\ \[list\ linsert\ \$v\ 0\]\ \$args\]\n\}\ \;#\ DKF\n======\n\n\[TR\]:\ \ You\ can\ also\ use\ `\[lreplace\]`\ where\ the\ first\ index\ is\ -1\ and\ the\ second\nis\ -2\ ...\ like\ so:\n\n======\nset\ myList\ \[list\ 0\ 1\ 2\]\nset\ myList\ \[lreplace\ \$myList\ -1\ -2\ 5\]\n#->\ 5\ 0\ 1\ 2\n======\n\n----\n\n\[GPS\]\ 2003:\ \ In\ the\ \[Tcl\ Chatroom\]\ I\ came\ up\ with\ this\ idea.\ \ You\ may\ find\ it\neasier\ than\ using\ lreplace\ to\ do\ the\ same.\n\n======\nproc\ remove.list.item\ \{lPtr\ i\}\ \{\n\ \ \ \ upvar\ \$lPtr\ l\;\ set\ l\ \[lreplace\ \$l\ \$i\ \$i\]\n\}\n======\n\nExample:\n\n======none\n%\ set\ l\ \[list\ a\ b\ c\]\ \na\ b\ c\n%\ remove.list.item\ l\ 1\na\ c\n%\ set\ l\na\ c\n======\n\n----\n\n'''Key-value\ list\ searching''':\ Before\ \[dict\]\ arrived,\ we\ could\ have\ a\ two-way\nmap\ key<->value\ like\ this:\n\n======\nproc\ kvsearch\ \{kvlist\ item\}\ \{\n\ \ \ \ set\ pos\ \[lsearch\ \$kvlist\ \$item\]\n\ \ \ \ if\ \{\$pos\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ lindex\ \$kvlist\ \[expr\ \{\$pos+1-2*(\$pos%2)\}\]\n\ \ \ \ \}\n\}\ \;#\ RS\n%\ kvsearch\ \{1\ one\ 2\ two\ 3\ three\}\ four\ \;#\ returns\ empty\ string/list\n%\ kvsearch\ \{1\ one\ 2\ two\ 3\ three\}\ 1\none\n0\ %\ kvsearch\ \{1\ one\ 2\ two\ 3\ three\}\ one\n1\n======\n\n----\n\n'''Pairs'''\ of\ members\ of\ a\ list:\n\n======\nproc\ pairs\ set\ \{\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ set\ last\ \[expr\ \{\[llength\ \$set\]-1\}\]\n\ \ \ \ for\ \{set\ ia\ 0\}\ \{\$ia\ <\ \$last\}\ \{incr\ ia\}\ \{\n\ \ \ \ \ \ \ \ foreach\ b\ \[lrange\ \$set\ \[expr\ \{\$ia+1\}\]\ end\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ res\ \[list\ \[lindex\ \$set\ \$ia\]\ \$b\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ res\n\}\ \;#\ RS\n%\ pairs\ \{a\ b\ c\ d\}\n\{a\ b\}\ \{a\ c\}\ \{a\ d\}\ \{b\ c\}\ \{b\ d\}\ \{c\ d\}\n======\n\nSimpler:\n\n======\nproc\ pairs\ set\ \{\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ foreach\ a\ \[lrange\ \$set\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ set\ set\ \[lrange\ \$set\ 1\ end\]\n\ \ \ \ \ \ \ \ foreach\ b\ \$set\ \{lappend\ res\ \[list\ \$a\ \$b\]\}\n\ \ \ \ \}\n\ \ \ \ set\ res\n\}\ \;#\ RS\n======\n\n\n----\n\n'''In-place\ queues'''\ using\ the\ \[K\]\ combinator\n\n======\nproc\ K\ \{a\ b\}\ \{set\ a\}\n##\n#\ Pop\ an\ item\ off\ a\ list,\ left\ or\ right\n#\nproc\ lpop\ \{how\ listName\}\ \{\n\ \ \ \ upvar\ \$listName\ list\n\ \ \ \ switch\ --\ \$how\ \{\n\ \ \ \ \ \ \ \ right\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ K\ \[lindex\ \$list\ end\]\ \[set\ list\ \[lrange\ \$list\ 0\ end-1\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ left\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ K\ \[lindex\ \$list\ 0\]\ \[set\ list\ \[lrange\ \$list\ 1\ end\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \{lpop\ right|left\ listName\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n##\n#\ Pop\ an\ item\ onto\ a\ list,\ left\ or\ right\n#\nproc\ lpush\ \{how\ listName\ item\}\ \{\n\ \ \ \ upvar\ \$listName\ list\n\ \ \ \ switch\ --\ \$how\ \{\n\ \ \ \ \ \ \ \ right\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ list\ \$item\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ left\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ list\ \[linsert\ \[K\ \$list\ \[set\ list\ \{\}\]\]\ 0\ \$item\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"lpush\ right|left\ listName\ item\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n======\n\nSee\ also\ \[Stacks\ and\ queues\],\ \[Implementing\ FIFO\ queues\]\ and\ \[Tcllib\]'s\ \[stack\]\nand\ \[queue\].\n\n----\n\n'''Flatten\ a\ list'''\ of\ any\ depth,\ i.e.\ remove\ all\ grouping:\n\nUse\ `\[\[::struct::list\ flatten\]`\ in\ \[tcllib\]\n\n======\n::struct::list\ flatten\ ?-full?\ ?--?\ sequence\n======\n\nThe\ subcommand\ takes\ a\ single\ sequence\ and\ returns\ a\ new\ sequence\ where\ one\ level\ of\ nesting\ was\ removed\ from\ the\ input\ sequence.\ In\ other\ words,\ the\ sublists\ in\ the\ input\ sequence\ are\ replaced\ by\ their\ elements.\n\nThe\ subcommand\ will\ remove\ any\ nesting\ it\ finds\ if\ the\ option\ -full\ is\nspecified.\n\n======none\n%\ ::struct::list\ flatten\ \{1\ 2\ 3\ \{4\ 5\}\ \{6\ 7\}\ \{\{8\ 9\}\}\ 10\}\n1\ 2\ 3\ 4\ 5\ 6\ 7\ \{8\ 9\}\ 10\n%\ ::struct::list\ flatten\ -full\ \{1\ 2\ 3\ \{4\ 5\}\ \{6\ 7\}\ \{\{8\ 9\}\}\ 10\}\n1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ 10\n======\n\nBut\ note\ that\ it\ may\ be\ inconsistent\ or\ otherwise\ counterintuitive:\n======\n%\ ::struct::list\ flatten\ -full\ \{1\ 2\ 3\ \{4\ 5\}\ \{6\ 7\}\ \{\{8\ 9\}\}\ 10\}\n1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ 10\n%\ ::struct::list\ flatten\ -full\ \{1\ 2\ 3\{4\ 5\}\ \{6\ 7\}\ \{\{8\ 9\}\}\ 10\}\n1\ 2\ 3\\\{4\ 5\\\}\ 6\ 7\ 8\ 9\ 10\n%\ ::struct::list\ flatten\ -full\ \{1\ 2\ 3\ \{4\ 5\}\{6\ 7\}\ \{\{8\ 9\}\}\ 10\}\nlist\ element\ in\ braces\ followed\ by\ \"\{6\"\ instead\ of\ space\n======\nIf\ '''3\\\{4\ 5\\\}'''\ then\ why\ not\ '''\\\{4\ 5\\\}\\\{6\ 7\\\}'''\ or\ even\ '''3\ 4\ 5'''\ and\ '''4\ 5\ 6\ 7'''?\n\nBecause\ `3\{4`\ and\ `5\}`\ are\ syntactically\ valid,\ which\ `\{4\ 5\}\{6`\ isn't\ (the\ closing\ brace\ that\ closes\ the\ initial\ opening\ brace\ isn't\ the\ last\ character\ in\ the\ word).\ `3\{4`\ and\ `5\}`\ can't\ be\ transformed\ into\ `3\ 4\ 5`\ since\ that\ would\ change\ the\ data\ content.\n\n\n\[HaO\]\ 2014-09-16:\ One\ may\ use\ 'concat\ \{*\}'\ to\ flatten\ a\ matrix\ by\ one\ level:\n======tcl\n%\ concat\ \{*\}\{1\ 2\ 3\ \{4\ 5\}\ \{6\ 7\}\ \{\{8\ 9\}\}\ 10\}\n1\ 2\ 3\ 4\ 5\ 6\ 7\ \{8\ 9\}\ 10\n======\n\n----\nIf\ 3\\\{4\ 5\\\}\ then\ why\ not\ \\\{4\ 5\\\}\\\{6\ 7\\\}\ or\ even\ 3\ 4\ 5\ and\ 4\ 5\ 6\ 7?\n\[MAK\]:\ \ Perhaps\ belongs\ in\ \[Additional\ string\ functions\],\ but:\nThis\ function\ takes\ a\ list\ of\ lists\ representing\ cell\ information\ for\ a\ table\n(i.e.,\ each\ element\ of\ the\ top-level\ list\ is\ a\ row\ of\ data,\ and\ each\ element\ of\nthose\ are\ individual\ columns\ of\ data)\ and\ generates\ text\ output\ with\ all\ of\ the\ncolumns\ aligned\ with\ each\ other.\ \ By\ default\ a\ single\ space\ is\ output\ between\nthe\ longest\ cell\ and\ the\ next\ one\;\ extra\ spaces\ can\ be\ added\ through\ the\noptional\ padding\ argument.\n\n======\nproc\ listToTable\ \{\ in\ \{padding\ 0\}\ \}\ \{\n\ \ \ \ set\ result\ \{\}\n\ \ \ \ array\ set\ lengths\ \{\}\n\ \ \ \ #\ Determine\ the\ longest\ element\ in\ each\ column\n\ \ \ \ foreach\ line\ \$in\ \{\n\ \ \ \ \ \ \ \ set\ colnum\ 1\n\ \ \ \ \ \ \ \ foreach\ column\ \$line\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ length\ \[string\ length\ \$column\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exist\ lengths(\$colnum)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$lengths(\$colnum)\ <\ \$length\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lengths(\$colnum)\ \$length\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lengths(\$colnum)\ \$length\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ colnum\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Format\ the\ output\n\ \ \ \ foreach\ line\ \$in\ \{\n\ \ \ \ \ \ \ \ set\ colnum\ 1\n\ \ \ \ \ \ \ \ set\ maxcol\ \[llength\ \$line\]\n\ \ \ \ \ \ \ \ foreach\ column\ \$line\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$colnum\ <\ \$maxcol\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ %-*s\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\$lengths(\$colnum)\ +\ 1\ +\ \$padding\}\]\ \$column\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \$column\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ colnum\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ append\ result\ \"\\n\"\n\ \ \ \ \}\n\ \ \ \ return\ \$result\n\}\n======\n\nExample:\n\n======none\n%\ listToTable\ \{a\ \{aaaa\ bb\ cccccc\}\ \{aaaaaa\ bbbbbbb\ cc\ ddddddd\}\ \{a\ b\ c\ d\}\}\na\naaaa\ \ \ bb\ \ \ \ \ \ cccccc\naaaaaa\ bbbbbbb\ cc\ \ \ \ \ ddddddd\na\ \ \ \ \ \ b\ \ \ \ \ \ \ c\ \ \ \ \ \ d\n======\n\n----\n\n\[AMG\]:\ \ \[interleave\]\ lets\ you\ combine\ parallel\ lists\ so\ you\ can\ pass\ them\ to\n\[\[array\ set\]\].\ \ \[\[listc\]\]\ and\ \[\[\[lcomp\]\]\]\ provide\ \[list\ comprehension\]s.\n\n----\n\n\[Sarnold\]:\ \ A\ command\ for\ '''splitting\ one\ list\ into\ segments'''\n\nInstead\ of\ doing:\n\n======\nset\ beginning\ \[lrange\ \$list\ 0\ end-\$size\]\nset\ end\ \[lrange\ \$list\ end-\[expr\ \{\$size-1\}\]\ end\]\n======\n\nwrite\ more\ understandable\ things\ like:\n\n======\nforeach\ \{beginning\ end\}\ \[lrange\ -split\ \$list\ end-\$size\]\ \{break\}\n======\n\nOf\ course,\ it\ may\ be\ implemented\ in\ pure\ tcl...\n\n----\n\nOk,\ so\ I'd\ propose\ also\ my\ extensions.\n\n'''Selects\ elements\ of\ a\ list\ on\ given\ positions\ and\ return\ them\ as\ a\ list'''.\n\n======none\n%set\ a\ \{one\ two\ three\ four\ five\}\n...\n%lselect\ \$a\ 0\ 3-4\none\ four\ five\n======\n\n======\nproc\ lselect\ \{list\ args\}\ \{\n\ \ \ \ set\ result\ \{\}\n\n\ \ \ \ foreach\ i\ \$args\ \{\n\ \ \ \ \ \ \ \ set\ range\ \[split\ \$i\ -\]\n\ \ \ \ \ \ \ \ if\ \{\ \[llength\ \$range\]\ ==\ 2\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ mset\ \{from\ to\}\ \$range\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ n\ \$from\}\ \{\$n\ <=\ \$to\}\ \{incr\ n\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ result\ \[lindex\ \$list\ \$n\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ result\ \[lindex\ \$list\ \$i\]\n\ \ \ \ \}\n\ \ \ \ return\ \$result\n\}\n======\n\n'''Splitting\ list\ at\ index:'''\n\n======\nproc\ lsplit\ \{ls\ index\}\ \{\n\ \ \ \ return\ \[\n\ \ \ \ \ \ \ \ list\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ lrange\ \$ls\ 0\ \[expr\ \{\$index-1\}\]\]\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ lrange\ \$ls\ \$index\ end\]\]\n\}\n======\n\nFunctional\ extensions:\n\n'''Filter\ each\ element\ through\ given\ command\ and\ return\ them\ as\ a\ list:'''\n\n======\nproc\ filter\ \{list\ cmd\}\ \{\n\ \ \ \ set\ result\ \{\}\n\ \ \ \ foreach\ i\ \$list\ \{\n\ \ \ \ \ \ \ \ lappend\ result\ \[eval\ \"\$cmd\ \{\$i\}\"\]\n\ \ \ \ \}\n\ \ \ \ return\ \$result\n\}\n======\n\n======none\n%set\ a\ \{\ \{\ \ \ \ 1\ \}\ \{\ 2\ \ \ \}\ \{\ 3\ \ \ \ \ \}\ \}\n...\n%filter\ \$a\ \"string\ trim\"\n1\ 2\ 3\n======\n\n\[HaO\]\ see\ \[lmap\]\ (new\ in\ tcl8.6)\n\n'''Return\ a\ list\ of\ elements\ that\ satisfy\ given\ predicate:'''\n\n======none\n%\ set\ l\ \{0\ 5\ 3\ 4\ 2\}\n0\ 5\ 3\ 4\ 2\n%\ select\ \$l\ \{expr\ 2<\}\n5\ 3\ 4\n======\n\n======\nproc\ select\ \{list\ pred\}\ \{\n\ \ \ \ set\ result\ \{\}\n\ \ \ \ \n\ \ \ \ foreach\ i\ \$list\ \{\n\ \ \ \ \ \ \ \ if\ \{\[eval\ \$pred\ \[list\ \$i\]\]\}\ \{lappend\ result\ \$i\}\n\ \ \ \ \}\n\ \ \ \ return\ \$result\n\}\n======\n\n\[MG\]\ offers\ an\ alternative\ version,\ that\ uses\ `\[uplevel\]`\ to\ evaluate\ `\$pred`\nin\ the\ caller's\ scope,\ and\ also\ uses\ `\[string\ map\]`\ to\ allow\ the\ value\ being\nchecked\ to\ placed\ anywhere\ in\ it\ (as\ '##')\ -\ it's\ called\ inside\ `\[expr\]`.\ The\nonly\ reason\ it\ uses\ `##`\ as\ the\ placeholder\ for\ the\ value\ is\ because\ I\ couldn't\nthink\ of\ a\ ''good'',\ more\ Tcl'ish\ way\ to\ do\ it,\ and\ that's\ what's\ used\ in\nanother\ language\ I\ use.\ If\ someone\ can\ think\ of\ a\ good\ way\ to\ do\ it\ that\ fits\nmore\ with\ the\ Tcl\ way,\ please\ change\ it.\n\n======\nproc\ select2\ \{list\ pred\}\ \{\n\ \ \ \ set\ result\ \[list\]\n\n\ \ \ \ foreach\ i\ \$list\ \{\n\ \ \ \ \ \ \ \ if\ \{\[uplevel\ 1\ \[list\ expr\ \[string\ map\ \[list\ ##\ \$i\]\ \$pred\]\]\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ result\ \$i\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$result\;\n\}\n======\n\n======none\n%\ set\ list1\ \{a\ b\ c\ d\ e\}\na\ b\ c\ d\ e\n%\ set\ list2\ \{c\ d\ e\ f\ g\}\nc\ d\ e\ f\ g\n%\ select2\ \$list1\ \{\[lsearch\ \$list2\ ##\]>-1\}\nc\ d\ e\n======\n\n\[Lars\ H\]\ thinks\ the\ Tcl\ way\ to\ do\ it\ is\ to\ have\ a\ variable\ that\ contains\ list\nitem\ to\ consider,\ thus:\n\n======\nproc\ select3\ \{var\ expr\ list\}\ \{\n\ \ \ \ upvar\ 1\ \$var\ item\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ foreach\ item\ \$list\ \{\n\ \ \ \ \ \ \ \ if\ \{\[uplevel\ 1\ \[list\ ::expr\ \$expr\]\]\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ res\ \$item\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$res\n\}\n======\n\nExample:\n\n======none\n%\ select3\ s\ \{\[string\ is\ integer\ \$s\]\}\ \{0\ 3\ x\ 0x3\ 09\ 35\ -7\ 0.\ 000\ 1e3\}\n0\ 3\ 0x3\ 35\ -7\ 000\n%\ select3\ s\ \{\$s\ !=\ 0\}\ \{0\ 3\ x\ 0x3\ 09\ 35\ -7\ 0.\ 000\ 1e3\}\n3\ x\ 0x3\ 09\ 35\ -7\ 1e3\n======\n\nHaving\ the\ list\ last\ makes\ it\ easy\ to\ define\ aliases:\n\n======none\n%\ interp\ alias\ \{\}\ nonzero\ \{\}\ select3\ s\ \{\$s!=0\}\n%\ nonzero\ \{0\ 3\ x\ 0x3\ 09\ 35\ -7\ 0.\ 000\ 1e3\}\n3\ x\ 0x3\ 09\ 35\ -7\ 1e3\n======\n\n\[NEM\]\ 2008-02-17:\ \ \ Would\ call\ the\ `filter`\ above\ `\[map\]`,\ and\ `select`\ would\nbe\ `\[filter\]`.\ I\ agree\ with\ \[Lars\ H\]\ about\ taking\ the\ list\ argument\ last\ (the\n\[tcllib\]\ version\ don't\ do\ this,\ alas).\ As\ an\ example:\n\n======\nproc\ filter\ \{p\ xs\}\ \{\n\ \ \ \ set\ ys\ \[list\]\n\ \ \ \ foreach\ x\ \$xs\ \{if\ \{\[uplevel\ #0\ \$p\ \[list\ \$x\]\]\}\ \{lappend\ ys\ \$x\}\}\n\ \ \ \ return\ \$ys\n\}\n#\ Usage:\nset\ xs\ \{0\ 3\ x\ 0x3\ 09\ 35\ -7\ 0.\ 000\ 1e3\}\nfilter\ \{string\ is\ integer\}\ \$xs\n#\ Simple\ aliases:\nproc\ let\ \{name\ =\ args\}\ \{interp\ alias\ \{\}\ \$name\ \{\}\ \{*\}\$args\}\nlet\ integers\ =\ filter\ \{string\ is\ integer\}\nintegers\ \$xs\ \;#\ Same\ result\n======\n\nMore\ complex\ expressions\ can\ easily\ be\ handled\ by\ \[lambda\]s:\n\n======\nproc\ func\ \{p\ b\}\ \{list\ ::apply\ \[list\ \$p\ \[list\ expr\ \$b\]\]\}\nfilter\ \[func\ x\ \{\$x\ !=\ 0\}\]\ \$xs\n======\n\n----\n\n\[FW\]:\ \ '''A\ more\ versatile\ key-value\ search'''\n\nThis\ function\ allows\ for\ searching\ an\ associative\ `\[dict\]`/`\[array\]`-style\nlist,\ with\ the\ added\ feature\ that\ the\ length\ of\ each\ \"row\"\ can\ be\ anything\n(instead\ of\ just\ 2:\ ''key\ value'')\ and\ you\ can\ pick\ which\ sub-index\ is\ used\ for\nthe\ key\ and\ for\ the\ value\ to\ retrieve.\ \ The\ first\ argument\ is\ the\ list,\ the\nsecond\ is\ the\ key\ to\ search\ for.\ \ Optional\ args:\ the\ third\ (default\ 2)\ is\ the\nlength\ of\ each\ row,\ the\ fourth\ (default\ 0)\ is\ the\ index\ within\ the\ row\ of\ the\nkey,\ and\ the\ fifth\ (default\ 1)\ is\ the\ index\ within\ the\ row\ of\ the\ value\ to\nretrieve.\ \ This\ proc\ requires\ an\ `\[lrepeat\]`\ proc\ (as\ offered\ above\;\ I've\ included\none\ here\ for\ completeness).\n\n======\nproc\ lrepeat\ \{val\ num\}\ \{\n\ \ \ \ set\ res\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$num\}\ \{incr\ i\}\ \{lappend\ res\ \$val\}\n\ \ \ \ return\ \$res\n\}\n\nproc\ lassoc\ \{list\ key\ \{rowsize\ 2\}\ \{keyind\ 0\}\ \{valind\ 1\}\}\ \{\n\ \ \ \ foreach\ \[lreplace\ \[lreplace\ \[lrepeat\ nullvar\ \$rowsize\]\ \\\n\ \ \ \ \ \ \ \ \$keyind\ \$keyind\ qkey\]\ \$valind\ \$valind\ qval\]\ \$list\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ equal\ \$qkey\ \$key\]\}\ \{return\ \$qval\}\n\ \ \ \ \}\n\ \ \ \ return\ -code\ error\ \{No\ match\ found.\}\n\}\n======\n\nExample:\n\n======\n#\ English,\ Dutch,\ French\nset\ phrases\ \[list\ \\\n\ \ \ \ Hi\ Hallo\ Bonjour\ \\\n\ \ \ \ \{I'll\ have\ the\ soup.\}\ \{Ik\ geef\ opdracht\ tot\ de\ soep.\}\ \\\n\ \ \ \ \ \ \ \ \{J'achèterai\ le\ potage\}\ \\\n\ \ \ \ Bye\ \{Tot\ ziens\}\ \{Au\ revoir\}\]\nputs\ \[lassoc\ \$phrases\ Hi\ 3\ 0\ 2\]\ \;#\ English\ to\ French\n======\n\n----\n\n\[Sarnold\]:\ \ I\ would\ like\ to\ filter\ elements\ when\ walking\ a\ list\ with\ `foreach`.\nSomething\ like\ this:\n\n======\nforeach-filter\ x\ \{\$x\ >\ 0\}\ \$list\ \{puts\ \"\$x\ is\ positive\"\}\n======\n\nThis\ improves\ over\ list\ comprehension\ for\ cases\ we\ do\ not\ want\ to\ walk\ the\nwhole\ list.\ (foreach\ is\ lazy)\n\n\[AK\]:\ \ I\ have\ no\ idea\ what\ you\ mean\ by\ 'foreach\ is\ lazy'.\ Can\ you\ elaborate\ ?\n\n`\[struct::list::\]::filterfor`\ is\ very\ similar,\ modulo\ arrangement\nof\ the\ arguments,\ and\ not\ using\ a\ script\ body\n\n\[Sarnold\]:\ \ I\ admit\ I\ abused\ the\ term\ 'lazy'\ but\ I\ meant\ that,\ in\ the\nfollowing:\ \n\n======\nforeach\ x\ \[filter\ \$hugelist\ cmd\]\ \{\n\ \ \ \ if\ \{\[somecmd\ \$x\]\}\ break\n\}\n======\n\nthe\ hugelist\ has\ to\ be\ filtered\ completely\ before\ the\ foreach\ is\ invoked,\nbecause\ of\ Tcl's\ eager\ evaluation.\ \ And\ the\ huge\ list\ is\ transformed\ even\ if\nonly\ one\ item\ is\ processed\ and\ the\ foreach\ loop\ is\ exited\ (via\ break).\ \ But\ the\nsame\ treatment\ could\ be\ optimized\ with\ the\ proposed\ foreach-filter:\n\n======\nforeach-filter\ x\ cmd\ \$hugelist\ \{\n\ \ \ \ if\ \{\[somecmd\ x\]\}\ break\n\}\n======\n\nCompared\ with\ the\ first\ version,\ it\ does\ not\ have\ to\ process\ \$hugelist\ totally,\nlike\ Haskell's\ list\ filters.\ \ (And\ Haskell\ works\ with\ ''lazy''\ evaluation)\ We\ncould\ build\ a\ similar\ foreach-map\ command.\n\n\[AK\]:\ \ Ok,\ now\ I\ understand.\ Both\ Tcl\ using\ 'strict'\ evaluation\ and\ the\ use\ncase\ you\ are\ looking\ for.\ Another\ possibility,\ but\ way\ more\ complex\ for\ the\ninternals\ would\ be\ the\ introduction\ of\ generators.\ Although,\ with\ Tcl\ 8.6's\ncoroutines\ we\ have\ a\ way\ of\ doing\ that\ already.\ Have\ the\ filter\ be\ a\ coroutine\nwhich\ yields\ each\ element\ as\ requested.\ Still,\ foreach\ is\ not\ prepared\ to\ ask\nfor\ elements\ one\ by\ one,\ it\ will\ always\ take\ the\ whole\ list.\ So\ even\ that\ is\nnot\ yet\ a\ workable\ way\ of\ partial\ processing\ of\ a\ computed/infinite\ list.\n\n\[LV\]:\ \ I\ am\ not\ certain,\ but\ would\ the\ \[foreach\ async\]\ discussion\ be\ a\ way\ of\ninteracting\ with\ the\ computed\ infinite\ generated\ lists?\ If\ so,\ then\ is\ this\nperhaps\ something\ that\ could\ appear\ in\ \[tcllib\]'s\ \[control\]\ module\ for\ use\ with\nTcl\ 8.6?\n\n\[MR\]:\ Wouldn't\ following\ suffice\ (unless\ Haskell-like\ /\ generators-like\nsemantics\ are\ really\ required)\ ?\n\n======\nforeach\ x\ \$lst\ \{\n\ \ \ \ if\ \{!\[predicate\ \$x\]\}\ continue\n\ \ \ \ if\ \{whatever\}\ break\n\ \ \ \ we_can_do_whatever_we_want_with\ \$x\ now\n\}\n======\n\nNaive\ implementation\ of\ foreach_filter\ would\ be:\n\n======\nproc\ foreach_filter\ \{varName\ lst\ predicate\ cmd\}\ \{\n\ \ \ \ uplevel\ 1\ \[list\ foreach\ \$varName\ \$lst\ \[list\ if\ \$predicate\ \$cmd\]\]\n\}\n\n======\n\nwhich,\ for\ the\ following\ test\ script:\n\n======\nforeach_filter\ x\ \{aa\ bb\ ab\ ac\}\ \{\[string\ index\ \$x\ 0\]\ ==\ \{a\}\}\ \{\n\ \ \ \ puts\ \$x\n\ \ \ \ if\ \{\$x\ ==\ \{ab\}\}\ break\n\}\n======\n\nyields\ following\ output:\n\n======none\naa\nab\n======\n\nie.\ `bb`\ is\ skipped\ by\ the\ filter\ and\ after\ encountering/printing\ `ab`\ \n`\[break\]`\ kicks\ in\ (hallelujah\ for\ Tcl\ metaprogramming\ !!!\ \;-))\n\n\[YOSIFOV\]:\n\nhttp://balkansoft.blogspot.ru/2012/10/traversing-over-paths.html%|%Original\ is\nhere%|%\n\nWalking\ on\ paths\ (like\ MS-DOS\ paths,\ but\ each\ path\ should\ be\ list\ of\ dirs,\ not\none\ string):\n\n======\nproc\ forpaths\ \{boundVarNames\ paths\ body\}\ \{\n#\ walk\ on\ paths,\ each\ is\ list\ of\ dirs.\ \$body\ will\ execute\ on\ visit\ each\ dir,\n#\ variables\ bound:\n#\ \ \ \$keyName\ -\ current\ path\n#\ \ \ \$levelName\ -\ current\ level\ (0...N)\n#\ \ \ \$leafName\ -\ is\ leaf\ or\ not\ (1,\ 0)\n\ \ \ \ foreach\ \{keyName\ levelName\ leafName\}\ \[lrange\ \$boundVarNames\ 0\ 2\]\ \{\}\n\ \ \ \ set\ group\ \[dict\ create\]\n\ \ \ \ foreach\ path\ \$paths\ \{\n\ \ \ \ \ \ \ \ dict\ set\ group\ \{*\}\$path\ @LEAF\n\ \ \ \ \}\n\n\ \ \ \ proc\ _cmp\ \{a\ b\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[expr\ \{\$a\ >\ \$b\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 1\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[expr\ \{\$a\ <\ \$b\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -1\n\ \ \ \ \ \ \ \ \}\ else\ \{return\ 0\}\n\ \ \ \ \}\n\n\ \ \ \ proc\ _trackpath\ \{track\ level\ dir\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\$track\ eq\ \{\}\}\ \{set\ track\ \[list\ @DUMMY\]\}\n\ \ \ \ \ \ \ \ switch\ --\ \[_cmp\ \[expr\ \$level+1\]\ \[llength\ \$track\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ 1\ \ \{lappend\ track\ \$dir\n\ \ \ \ \ \ \ \ \ \ \ \ 0\ \ \{lset\ track\ end\ \$dir\}\n\ \ \ \ \ \ \ \ \ \ \ \ -1\ \{set\ track\ \[lreplace\ \$track\ \$level\ end\ \$dir\]\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$track\n\ \ \ \ \}\n\ \ \ \ set\ gtrack\ \{\}\;\ #\ current\ path\ when\ visit\ each\ node\n\n\ \ \ \ proc\ _walk\ \{d\ keyName\ levelName\ leafName\ body\ \{_deep\ 2\}\}\ \{\n\ \ \ \ #\ here\ \$level\ is\ level\ in\ tree,\ not\ in\ stack\n\ \ \ \ #\ \$_deep\ is\ level\ in\ stack\n\ \ \ \ \ \ \ \ upvar\ \$_deep\ \$keyName\ key\ \$levelName\ level\n\ \ \ \ \ \ \ \ upvar\ gtrack\ gtrack\n\ \ \ \ \ \ \ \ if\ \{\$leafName\ ne\ \{\}\}\ \{\ upvar\ \$_deep\ \$leafName\ leaf\ \}\n\ \ \ \ \ \ \ \ dict\ for\ \{k\ v\}\ \$d\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ level\ \[expr\ \{\$_deep-2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ gtrack\ \[_trackpath\ \$gtrack\ \$level\ \$k\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ key\ \$gtrack\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$v\ eq\ @LEAF\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leaf\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uplevel\ \$_deep\ \$body\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ nested\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leaf\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uplevel\ \$_deep\ \$body\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ _walk\ \$v\ \$keyName\ \$levelName\ \$leafName\ \$body\ \[expr\ \{\$_deep+1\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ _walk\ \$group\ \$keyName\ \$levelName\ \$leafName\ \$body\n\}\n======\n\nAnd\ usage\ something\ like\ this:\n\n======\nforpaths\ \{key\ level\ leaf\}\ \$dirs\ \{...\}\n#\ OR\nforpaths\ \{key\ level\}\ \$dirs\ \{...\}\n#\ OR\nforpaths\ key\ \$dirs\ \{...\}\n======\n\n''Find\ the\ difference\ between\ two\ lists''\n\n======\nproc\ ldiff\ \{a\ b\}\ \{\n\ \ \ \ lmap\ elem\ \$a\ \{\ expr\ \{\$elem\ in\ \$b\ ?\ \[continue\]\ :\ \$elem\}\ \}\n\}\n======\n\n----\n\[AMG\]:\ '''Sorting\ a\ list\ by\ element\ string\ length'''\n\n======\nlsort\ -command\ \{apply\ \{\{a\ b\}\ \{expr\ \{\[string\ length\ \$a\]\ -\ \[string\ length\ \$b\]\}\}\}\}\ \$list\n======\n\n----\n'''\[domino\]\ -\ 2018-05-25\ 16:30:34'''\n\n(First\ time\ edit\;\ forgive\ formatting\ and\ \"where\ on\ the\ page\"\ issues)\n\nRe:\ LPREPEND,\ couldn't\ you\ just\ use\ this?\n\nAll\ produce\ the\ properly-appended\ lists\ (obeying\ listed-ness):\n\ \ \ \ \ \ \ \ -->\ \"\{10\ 11\ 12\ 13\ 14\}\ 25\ \{100\ 101\ 102\ 103\ 104\}\ \{\{10\ 11\ 12\ 13\ 14\}\}\ 0\ 1\ 2\ 3\ 4\"\nNumbers\ given\ (in\ ms):\ (\ 5\ single\ iterations:\ quickest\ ->\ slowest)\ /\ (\ time\ \{code\}\ 1000\ \[iterations\]\ )\nTCL8.6.7\n======\nproc\ lprependDKF\ \{\ var_name\ args\ \}\ \{ regexp2} CALL {my render {Additional list functions} '''Additional\ \[list\]\ functions'''\ \ is\ a\ guide\ to\ pages\ that\ provide\ commands\ and\nscripts\ or\ present\ methods\ for\ manipulating\ \[list%|%lists\].\n\n\n\n**\ Command\ Suites\ **\n\nCollections\ of\ list\ commands.\n\n\ \ \ \[aqtools\]:\ \ \ \n\n\ \ \ \[ExtraL\]:\ \ \ \n\n\ \ \ \[fptools\]:\ \ \ `lcompare`,\ `lempty?`,\ `lmultirange`,\ `lreduce`,\ `lsample`,\ `lshift!`,\ `match`\ (for\ \[pattern\ matching\]\ on\ lists)\ and\ others.\n\n\ \ \ \[https://web.archive.org/web/20080625075946/http://www.han.de/~racke/jultaf/jultaf.html%|%Jumble\ Library\ for\ Tcl\ and\ Friends\],\ by\ Stefan\ Hornburg:\ \ \ `shift`,\ `pop`,\ `append`,\ `assign`,\ `match`\n\n\ \ \ \[Listx\]:\ \ \ Provides\ the\ essential\ extended\ set\ of\ list\ operations.\ Today,\ most\ are\ in\ Tcl\ itself.\n\n\ \ \ \[Listex\],\ by\ \[Stuart\ Cassoff\]:\ \ \ `lPluck`,\ `lDivide`,\ `lDivideAtStr`,\ `lUInterleave`,\ `lMaxelementLength`.\n\n\ \ \ \[ftp://ccfadm.eeg.ccf.org/pub/ctk/mtcl.tar.gz%|%mtcl\]:\ \ \ (\[HaO\]\ 2010-08-24:\ dead\ link\ for\ me)\n\n\n\ \ \ \[http://www.purl.org/net/akupries/soft/pool/index.htm%|%Pool\]:\ \ \ \n\n\ \ \ \[http://www.purl.org/net/akupries/soft/pool/pkg_Pool_Base.htm%|%Pool_Base\]:\ \ \ \n\n\ \ \ \[tcllib%|%tcllib's\]\ \[struct::list\]:\ \ \ \n\n\ \ \ \[TclX\]:\ \ \ Search\ the\ \[http://www.tcl.tk/man/tclx8.2/TclX.n.html%|%documentation\]\ for\ ''LIST\ MANIPULATION\ COMMANDS''.\n\n\ \ \ \[underscore.tcl\]:\ \ \ \n\n\ \ \ \[ycl\]::list:\ \ \ provides\ commands\ such\ as\ `dedent`,\ `any`,\ `all`,\ `are`,\ `filter`,\ `pick`,\ `\[scripted\ list%|%sl\]`,\ and\ `which`.\n\n\n\n**\ Modification\ Commands\ **Commands\ that\ modify\ the\ content\ of\ a\ list.\n\n\ \ \ *\ \[lpop\]:\ \ \ \n\ \ \ \[lpop\]:\ \ \ \n\n\ \ \ \[lremove\]:\ \ \ \n\n\ \ \ \[lshift\ -Adding\ Unique\ Items\ to\ Lists\ of\ Fixed\ Length\]:\ \ \ \n\n\n\n\ \ \ *\ \[another\ list\ comprehension\]:\ \ \ \n\ \ \ *\ \[Finding\ a\ sublist\]:\ \ \ \n\n\ \ \ \[another\ list\ comprehension\]:\ \ \ \n**\ Traversal\ Commands\ **Commands\ that\ visit\ elements\ in\ a\ list.\n\ \ \ \[Finding\ a\ sublist\]:\ \ \ \n\n\ \ \ \[lazy\ lists\]:\ \ \ \n\n\ \ \ \[List\ Comprehension\]:\ \ \ \n\n\ \ \ \[list\ map\ and\ list\ grep\]:\ \ \ two\ operations\ implemented\ (over-)simply\ in\ Tcl.\n\n\ \ \ \[lswitch\]:\ \ \ Like\ `\[switch\]`,\ but\ each\ ''pattern''\ is\ a\ list\ of\ patterns\ to\ match\ against\ the\ item\ in\ ''string''\ at\ the\ corresponding\ position.\ All\ switch\ options\ are\ supported.\n\n\ \ \ \[range\],\ by\ \[Salvatore\ Sanfilippo\]:\ \ \ \[Python\]-like\ range\ operation.\n\n\ \ \ \[Recursive\ list\ searching\]:\ \ \ \n\n\ \ \ \[Striding\ a\ list\]:\ \ \ \n\n\n\n\ \ \ *\ \[Use\ while\ to\ iterate\ over\ a\ list\]:\ \ \ \n\n\n\ \ \ \[Use\ while\ to\ iterate\ over\ a\ list\]:\ \ \ \n**\ Reording\ Commands\ **Commands\ that\ reorder\ the\ elements\ of\ a\ list.\n\n\ \ \ *\ \[randomizing\ a\ list\]:\ \ \ \n\ \ \ *\ \[Shuffle\ a\ list\]:\ \ \ \n\ \ \ *\ \[Shuffle\ a\ list:\ graph\ results\]:\ \ \ \n\ \ \ *\ \[Shuffling\ a\ list\]:\ \ \ \n\ \ \ \[randomizing\ a\ list\]:\ \ \ \n\ \ \ *\ \[list\ stripping\]:\ \ \ \n\ \ \ \[Shuffle\ a\ list\]:\ \ \ \n\n\ \ \ \[Shuffle\ a\ list:\ graph\ results\]:\ \ \ \n\ \ \ \n\ \ \ \[Shuffling\ a\ list\]:\ \ \ \n\n\ \ \ \[Sorted\ Lists\]:\ \ \ \n\n\ \ \ \[lrotate%|%Rotate\ a\ list%|%\]:\ \ \ \n\n\ \ \ *\ \[List\ trim\]:\ \ \ \n\ \ \ *\ \[lsplit\]:\ \ \ creates\ two\ lists\ from\ a\ single\ list\ and\ a\ test\ expression\ \n\ \ \ *\ \[MakeRanges\]:\ \ \ Takes\ a\ list\ of\ numbers\ and\ makes\ them\ into\ a\ a\ list\ of\ number\ ranges.\n\ \ \ \[Concatenating\ lists\]:\ \ \ \n\ \ \ *\ \[AsserTcl\]:\ \ \ Supports\ quantifier\ commands\ to\ test\ whether\ an\ expressions\ holds\ universally\ or\ existentially\ over\ a\ data\ structure\ such\ as\ a\ list\ or\ array\ aggreggate\ data\ structure.\n\ \ \ \[list\ stripping\]:\ \ \ \n\ \ \ *\ \[Cartesian\ product\ of\ a\ list\ of\ lists\]:\ \ \ \n\ \ \ \[List\ trim\]:\ \ \ \n\ \ \ *\ \[Counting\ Elements\ in\ a\ List\]:\ \ \ \n\ \ \ \[lsplit\]:\ \ \ creates\ two\ lists\ from\ a\ single\ list\ and\ a\ test\ expression\ \n\n\ \ \ \[MakeRanges\]:\ \ \ Takes\ a\ list\ of\ numbers\ and\ makes\ them\ into\ a\ a\ list\ of\ number\ ranges.\n\n\ \ \ \[nested\ list\ join\]:\ \ \ \n\n\ \ \ \[permutations\]:\ \ \ \n\n\ \ \ \[Power\ set\ of\ a\ list\]:\ \ \ \n\n\ \ \ \[split\ and\ join\ for\ nested\ lists\]:\ \ \ \n\n\ \ \ \[Using\ expr\ on\ lists\]:\ \ \ \n\n\ \ \ \[Summing\ a\ list\]:\ \ \ \n\n\ \ \ \[Unique\ Element\ List\]:\ \ \ \n\n\ \ \ \[lolcat\]:\ \ \ Process\ a\ list\ into\ another\ list\ that\ contains\ more\ values\ than\ the\ original\ list.\n\n\n\n\ \ \ *\ \[Depth\ of\ a\ list\]:\ \ \ \n\ \ \ *\ \[diff\ in\ Tcl\]:\ \ \ longest\ common\ subsequence\n\ \ \ *\ \[ftp://ftp.tcl.tk/pub/tcl/mirror/ftp.procplace.com/sorted/packages-7.6/devel/keylprint.README%|%key\ list\ printing\ procedures\]:\ \ \ pretty\ prints\ Tclx's\ \[http://www.tcl.tk/man/tclx8.2/TclX.n.html%|%key\ lists\].\n\ \ \ \[AsserTcl\]:\ \ \ Supports\ quantifier\ commands\ to\ test\ whether\ an\ expressions\ holds\ universally\ or\ existentially\ over\ a\ data\ structure\ such\ as\ a\ list\ or\ array\ aggreggate\ data\ structure.\n\ \ \ *\ \[Complex\ data\ structures\]\ for\ \[struct\]:\ \ \ Named\ access\ to\ list\ positions.\n\ \ \ \[Cartesian\ product\ of\ a\ list\ of\ lists\]:\ \ \ \n\ \ \ *\ \[Decision\ trees\]:\ \ \ \n\ \ \ \[Counting\ Elements\ in\ a\ List\]:\ \ \ \n\ \ \ *\ \[keyed\ list\]:\ \ \ \n\ \ \ \[Depth\ of\ a\ list\]:\ \ \ \n\n\ \ \ \[diff\ in\ Tcl\]:\ \ \ longest\ common\ subsequence\n\n\ \ \ \[ftp://ftp.tcl.tk/pub/tcl/mirror/ftp.procplace.com/sorted/packages-7.6/devel/keylprint.README%|%key\ list\ printing\ procedures\]:\ \ \ pretty\ prints\ Tclx's\ \[http://www.tcl.tk/man/tclx8.2/TclX.n.html%|%key\ lists\].\n\n\ \ \ \[ldiff\]:\ \ \ Find\ the\ difference\ of\ two\ lists.\n\n\ \ \ \[lexpr\]:\ \ \ \n\n\ \ \ \[list\ level\]:\ \ \ \n\n\ \ \ \[ldiff\],\ by\ \[PL\]:\ \ \ Find\ the\ difference\ of\ two\ lists.\n\n\ \ \ \[plist\]:\ \ \ is\ for\ lists\ what\ `\[parray\]`\ is\ for\ arrays.\n\n\n\n\ \ \ *\ \[linked\ lists\]:\ \ \ \n\ \ \ *\ \[Chart\ of\ proposed\ list\ functionality\]:\ \ \ \n\ \ \ \[Binary\ trees\]:\ \ \ \n\ \ \ *\ \[internal\ organization\ of\ the\ list\ extension\]:\ \ \ \n\ \ \ \[Bit\ vectors\]:\ \ \ Can\ nicely\ be\ implemented\ with\ lists.\n\ \ \ *\ \[list\]:\ \ \ Contains\ (pointers\ to\ other\ Tcl\ specific\ list\ related\ commands.\n\ \ \ \[Complex\ data\ structures\]\ for\ \[struct\]:\ \ \ Named\ access\ to\ list\ positions.\n\n\ \ \ \[Decision\ trees\]:\ \ \ \n\n\ \ \ \[keyed\ list\]:\ \ \ \n\n\ \ \ \[linked\ lists\]:\ \ \ \n\n\ \ \ \[nxs\]:\ \ \ Nested\ heterogeneous\ data\ structures.\n\n\ \ \ \[set\ operations\ for\ Tcl\ lists\]:\ \ \ \n\n\ \ \ \[Stacks\ and\ queues\]:\ \ \ \n\n\ \ \ \[trees\ as\ nested\ lists\]:\ \ \ \n\n\ \ \ \[yet\ another\ stack\ package\]:\ \ \ \n\n\n\n\ \ \ *\ \[Showing\ sublists\]:\ \ \ In\ a\ listbox.\n\n\ \ \ \[Chart\ of\ existing\ list\ functionality\]:\ \ \ \n\n\ \ \ \[Chart\ of\ proposed\ list\ functionality\]:\ \ \ \n\[LV\]:\ Anyone\ have\ a\ URL\ for\ this\ ''posting''\ of\ forest.tcl\ ?\n\ \ \ \[internal\ organization\ of\ the\ list\ extension\]:\ \ \ \n\n\ \ \ \[list\]:\ \ \ Contains\ (pointers\ to\ other\ Tcl\ specific\ list\ related\ commands.\n\n\ \ \ \[Showing\ sublists\]:\ \ \ In\ a\ listbox.\n\n\n\n----\n\nOutline\ of\ the\ next\ steps\ to\ do:\n\n\ \ \ *\ Go\ through\ extensions\ listed\ above\ and\ collect\ all\ of\ their\ functionality\ in\ a\ table.\ Group\ equal\ and/or\ similar\ functionality\ together.\ \[Chart\ of\ existing\ list\ functionality\]\n\ \ \ *\ Define\ the\ functionality\ we\ want\ to\ have\ in\ the\ official\ extension.\ (Or\ shall\ we\ skip\ this\ in\ favor\ of\ a\ '''take\ all'''\ approach\ ?).\ --\ AK:\ No.\ After\ looking\ at\ the\ available\ functionality\ I\ believe\ that\ some\ parts\ may\ need\ a\ little\ pruning.\ \[Chart\ of\ proposed\ list\ functionality\].\n\ \ \ *\ Implement\ the\ functionality.\n\nAreas\ of\ discussion:\n\n\ \ \ *\ What\ functionality\ is\ provided,\ what\ do\ we\ want,\ what\ is\ missing,\ or\ superfluous\ ?\ LV\ already\ started\ a\ wishlist,\ see\ below.\n\ \ \ *\ \[Internal\ organization\ of\ the\ list\ extension\],\ commenting\ style,\ which\ namespace,\ ...\n\n----\n\n\[LV\]:\ \ Another\ useful\ thing\ would\ be\ a\ 'wishlist'\ (excuse\ the\ pun)\ of\nfunctionality\ requested.\ \ This\ would\ include\ things\ like\ (all\ of\ these\ have,\ in\nthe\ past,\ either\ been\ posted\ to\ the\ newsgroup\ or\ offered\ by\ a\ contributor\ to\nthe\ newsgroup\ -\ so\ if\ code\ is\ desired,\ the\ contacts\ listed\ in\n\[http://www.purl.org/net/tcl-faq/part5.html\]\ should\ be\ emailed.):\n\n\ \ \ \ *\ \[lassign\]\ -\ Assign\ \[elements\]\ of\ list\ to\ the\ given\ variables.\ --\ AK:\ Already\ provided\ by\ some\ extensions.\ RS:\ ...\ or\ \[foreach\].\ \[DKF\]:\ In\ the\ core\ in\ 8.5.\n\ \ \ \ *\ linear\ sort\ on\ list\ of\ lists\ -\ Alphanumeric\ comparison\ for\ linear\ sort\ of\ lists.\ --\ AK:\ '''???'''\ \[Lars\ H\]:\ Does\ this\ mean\ lexicographic\ sort?\ To\ compare\ elements\ L1\ and\ L2,\ first\ compare\ their\ first\ elements\ \[\[lindex\ \$L1\ 0\]\]\ and\ \[\[lindex\ \$L2\ 0\]\].\ If\ these\ are\ equal,\ compare\ the\ second\ elements,\ and\ so\ on.\n\ \ \ \ *\ Linked\ list\ support.\ I\ (AK)\ had\ a\ problem\ here,\ but\ Larry\ solved\ it\ for\ me.\ Meant\ is\ stack/queue-like\ access\ to\ the\ list.\ Some\ extensions\ already\ provide\ this\ functionality:\ \[yet\ another\ stack\ package\].\n\ \ \ \ *\ Remove\ empty\ elements\ from\ list.\ --\ '''NEW'''.\ Added\ to\ proposed\ list\ of\ functions.\n\ \ \ \ *\ Given\ one\ list,\ create\ a\ new\ list\ consisting\ only\ of\ the\ unique\ elements.\ --\ AK:\ Provided\ by\ some\ extensions.\ \[Lars\ H\]:\ How\ is\ this\ different\ from\ \[\[lsort\ -unique\]\]?\n\ \ \ \ *\ Even\ better\ -\ provide\ list\ sorting\ capability\ equal\ or\ greater\ than\ Unix\ sort-\ --\ '''NEW'''.\ AK:\ This\ will\ be\ difficult.\n\ \ \ \ *\ tclX\ code\ to\ return\ subsets\ of\ lists,\ based\ on\ patterns.\ --\ AK:\ Provided\ by\ some\ extensions,\ but\ most\ not\ as\ complete\ as\ \[TclX\].\ (\[DKF\]:\ This\ can\ be\ done\ with\ \[lsearch\]\;\ '''\[\[lsearch\ -all\ -inline\ -glob\ \$theList\ \$theGlobPattern\]\]''')\n\ \ \ \ *\ parse\ a\ list\ into\ variables\ similar\ to\ the\ way\ a\ command\ line\ is\ parsed.\ --\ AK:\ getopt-like,\ place\ in\ that\ extension.\n\ \ \ \ *\ Compare\ two\ lists\ for\ equality.\ --\ '''NEW'''.\ AK:\ Looks\ so\ innocent.\ What\ is\ equality\ ?\ With\ order\ ?\ Without\ ?\ What\ about\ duplicates\ ?\ These\ are\ several\ functions.\ Not\ yet\ in\ the\ proposed\ list.\n\ \ \ \ *\ A\ number\ of\ people\ have\ written\ a\ variety\ of\ 'database\ query\ results'\ to\ 'list'\ type\ interfaces.\ \ I\ wonder\ if\ something\ generic\ could\ be\ created.\n\ \ \ \ *\ Transpose\ elements\ within\ list\ of\ lists\ --\ AK:\ Primitives\ for\ that\ already\ provided\ by\ some\ extensions.\n\ \ \ \ *\ \[ulis\]:\ ldelete\ list-name\ ?index...?,\ remove\ the\ items\ in\ place.\n\ \ \ \ *\ \[ulis\]:\ leval\ \$list,\ eval\ without\ concat.\ \ \[DKF\]:\ In\ Tcl\ 8.5,\ just\ use\ '''\[\[\{*\}\$list\]\]'''\ which\ is\ now\ part\ of\ the\ core\ language\ syntax.\n\n----\n\n\[AK\]:\ \ I\ have\ to\ admit\ that\ I\ currently\ see\ ''keyed\ lists''\ as\ something\ to\neither\ add\ later,\ or\ to\ place\ them\ into\ a\ separate\ extension.\n\n\[AK\]:\ \ I\ would\ also\ vote\ to\ definitely\ place\ DB\ interfaces\ into\ their\ own\nextension.\n\nDL:\ \ also\ look\ at\ list\ utilities\ in\ the\ opt\ package\ of\ tcl\ 8.\[\[01\]\]\ (mostly\ntclX\ 'compatible'\ though)\n\n----\n\n\[Nat\ Pryce\]:\ \ I\ have\ implemented\ ''map'',\ ''fold''\ and\ ''zip''\ functions\ in\ C\nand\ ''lambda''\ functions\ in\ Tcl,\ but\ never\ released\ them.\ \ Anyone\ who\ is\nworking\ on\ a\ list\ extension\ package\ is\ welcome\ to\ the\ code.\n\n----\n\n\[Larry\ Virden\]:\ the\ following\ pages\ have\ recently\ appeared\ on\ the\ Wiki:\n\[Shuffle\ a\ list\],\ \[Striding\ a\ list\],\ \[Summing\ a\ list\]\ -\ \[Cartesian\ product\ of\ a\nlist\ of\ lists\]\ \[Recursive\ list\ searching\]\n\n----\n\nHere's\ some\ little\ helpers\ just\ for\ taking\ out:\n\n'''List\ element''':\n\n======\nproc\ lel\ \{L\ element\}\ \{expr\ \{\[lsearch\ \$L\ \$element\]>=0\}\}\n======\n\n======\npackage\ require\ Tcl\ 8.5\nproc\ lel\ \{L\ element\}\ \{\ expr\ \{\ \$element\ in\ \$L\ \}\ \}\n======\n\nThough\ if\ you\ have\ Tcl8.5\ you\ should\ write\ `if\ \{\$elt\ in\ \$list\}\ ...`\ rather\ than\ `if\ \{\[\[lel\ \$list\ \$elt\]\]\}\ ...`.\n\n'''Add\ an\ element\ to\ a\ list'''\ only\ if\ not\ present\ yet:\n\n======\nproc\ ladd\ \{_L\ args\}\ \{\n\ \ \ \ upvar\ \$_L\ L\n\ \ \ \ if\ \{!\[info\ exists\ L\]\}\ \{set\ L\ \{\}\}\n\ \ \ \ foreach\ i\ \$args\ \{if\ \{!\[lel\ \$L\ \$i\]\}\ \{lappend\ L\ \$i\}\}\n\}\n======\n\n'''Random\ element'''\ selected\ from\ a\ list:\n\n======\nproc\ lrandom\ L\ \{lindex\ \$L\ \[expr\ \{int(rand()*\[llength\ \$L\])\}\]\}\n======\n\n'''Random\ element'''\ drawn\ (and\ removed)\ from\ a\ list:\n\n======\nproc\ ldraw\ \{_L\}\ \{\n\ \ \ \ upvar\ 1\ \$_L\ L\n\ \ \ \ set\ pos\ \[expr\ \{int(rand()\ *\ \[llength\ \$L\])\}\]\n\ \ \ \ set\ res\ \[lindex\ \$L\ \$pos\]\n\ \ \ \ set\ L\ \[lreplace\ \$L\ \$pos\ \$pos\]\n\ \ \ \ set\ res\n\}\n======\n\n'''Remove\ elements\ from\ a\ list'''\ by\ value:\n\n======\nproc\ lremove\ \{_L\ args\}\ \{\n\ \ \ upvar\ \$_L\ L\n\ \ \ foreach\ i\ \$args\ \{\n\ \ \ \ \ \ \ set\ pos\ \[lsearch\ \$L\ \$i\]\ \;#\ might\ be\ -1\ if\ not\ found...\n\ \ \ \ \ \ \ set\ L\ \[lreplace\ \$L\ \$pos\ \$pos\]\ \;#\ ...\ but\ that's\ fine\n\ \ \ \}\n\}\n======\n\n'''\[lreverse%|%Reverse\]\ the\ order\ of\ a\ list''':\n\nSince\ 8.5,\ `\[lreverse\]`\ is\ a\ \[Tcl\ Commands%|%built-in\]\ Tcl\ command.\n\n======\nproc\ lreverse\ L\ \{\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ set\ i\ \[llength\ \$L\]\n\ \ \ \ #while\ \{\[incr\ i\ -1\]>=0\}\ \{lappend\ res\ \[lindex\ \$L\ \$i\]\}\n\ \ \ \ while\ \{\$i\}\ \{lappend\ res\ \[lindex\ \$L\ \[incr\ i\ -1\]\]\}\ \;#\ rmax\n\ \ \ \ set\ res\n\}\ \;#\ RS,\ tuned\ 10%\ faster\ by\ \[rmax\]\n======\n\nHere's\ a\ simpler\ way\ to\ do\ it.\n\n======\nproc\ lreverse2\ l\ \{\n\ \ \ \ set\ ret\ \{\}\n\ \ \ \ foreach\ i\ \$l\ \{\n\ \ \ \ \ \ \ \ set\ ret\ \[linsert\ \$ret\ 0\ \$i\]\n\ \ \ \ \}\n\ \ \ \ return\ \$ret\n\}\ #EAS\n======\n\n\[RS\]:\ \ Note\ however\ that\ the\ `\[linsert\]`\ requires\ copying\ the\ whole\ sublist\ N\ntimes,\ while,\ the\ `\[lappend\]`\ copies\ each\ element\ exactly\ once.\n\n\[KPV\]:\ \ Here\ are\ three\ more\ ways\ of\ reversing\ a\ list\ that\ utilize\ \[lset\]\ to\nswap\ pairs\ of\ elements\ in\ place:\n\n======\nproc\ lreverse3\ \{l\}\ \{\n\ \ \ \ set\ start\ -1\n\ \ \ \ set\ end\ \[llength\ \$l\]\n\n\ \ \ \ while\ \{\[incr\ start\]\ <\ \[incr\ end\ -1\]\}\ \{\n\ \ \ \ \ \ \ \ set\ tmp\ \[lindex\ \$l\ \$start\]\n\ \ \ \ \ \ \ \ lset\ l\ \$start\ \[lindex\ \$l\ \$end\]\n\ \ \ \ \ \ \ \ lset\ l\ \$end\ \$tmp\n\ \ \ \ \}\n\ \ \ \ return\ \$l\n\}\n======\n\nFor\ long\ lists\ you\ can\ squeeze\ out\ a\ bit\ more\ performance\ with\ the\ help\ of\n`\[foreach\]`:\n\n======\nproc\ lreverse4\ \{l\}\ \{\n\ \ \ \ set\ start\ -1\n\ \ \ \ set\ end\ \[llength\ \$l\]\n\ \ \ \ \n\ \ \ \ foreach\ tmp\ \$l\ \{\n\ \ \ \ \ \ \ \ if\ \{\[incr\ start\]\ >=\ \[incr\ end\ -1\]\}\ break\n\ \ \ \ \ \ \ \ lset\ l\ \$start\ \[lindex\ \$l\ \$end\]\n\ \ \ \ \ \ \ \ lset\ l\ \$end\ \$tmp\n\ \ \ \ \}\n\ \ \ \ return\ \$l\n\}\n======\n\nHere's\ a\ very\ simple\ version\ —\ faster\ than\ `lreverse4`\ but\ alas\ not\ the\nfastest:\n\n======\nproc\ lreverse5\ \{l\}\ \{\n\ \ \ \ set\ end\ \[llength\ \$l\]\n\ \ \ \ foreach\ tmp\ \$l\ \{\n\ \ \ \ \ \ \ \ lset\ l\ \[incr\ end\ -1\]\ \$tmp\n\ \ \ \ \}\n\ \ \ \ return\ \$l\n\}\n======\n\n\[Lars\ H\]:\ \ This\ is\ not\ fast,\ but\ it\ avoids\ index\ arithmetic.\ \ The\ idea\ can\ be\nnice\ in\ cases\ where\ you\ want\ to\ process\ the\ list\ elements\ while\ reversing\ their\norder.\n\n======\nproc\ lreverse6\ \{l\}\ \{\n\ \ \ \ set\ stack\ \{\}\n\ \ \ \ foreach\ item\ \$l\ \{set\ stack\ \[list\ \$stack\ \$item\]\}\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ while\ \{\[llength\ \$stack\]\}\ \{\n\ \ \ \ \ \ \ foreach\ \{stack\ item\}\ \$stack\ break\n\ \ \ \ \ \ \ lappend\ res\ \$item\n\ \ \ \ \}\n\ \ \ \ return\ \$res\n\}\n======\n\n\n'''Sort\ a\ list\ on\ multiple\ indices''':\n\n======\nproc\ multisort\ \{indices\ L\ args\}\ \{\n\ \ \ \ set\ cmd\ \"list\ \$L\"\n\ \ \ \ foreach\ i\ \[lreverse\ \$indices\]\ \{\n\ \ \ \ \ \ \ set\ cmd\ \"lsort\ \$args\ -index\ \$i\ \\\[\$cmd\\\]\"\n\ \ \ \ \}\n\ \ \ \ eval\ \$cmd\n\}\ \;#\ RS\n======\n\n======none\n%\ multisort\ \{2\ 0\ 1\}\ \ \{\{abe\ zyx\ 25\}\ \{john\ smith\ 14\}\ \{harold\ brown\ 99\}\ \{mary\ jones\ 32\}\}\n\{john\ smith\ 14\}\ \{abe\ zyx\ 25\}\ \{mary\ jones\ 32\}\ \{harold\ brown\ 99\}\n%\ multisort\ \{0\ 2\ 1\}\ \ \{\{abe\ zyx\ 25\}\ \{john\ smith\ 14\}\ \{harold\ brown\ 99\}\ \{mary\ jones\ 32\}\}\ -decreasing\n\{mary\ jones\ 32\}\ \{john\ smith\ 14\}\ \{harold\ brown\ 99\}\ \{abe\ zyx\ 25\}\n======\n\nsee\ also:\ \[Custom\ sorting\]\n\n----\n\n'''Permute\ a\ list''':\ \ returns\ a\ list\ of\ the\ possible\ orderings\ of\ the\ input\nlist,\ e.g.\ `lpermute\ \{a\ b\ c\}\ =>\ \{\{a\ b\ c\}\ \{a\ c\ b\}\ \{b\ a\ c\}\ \{b\ c\ a\}\ \{c\ a\ b\}\ \{c\ b\na\}\}`.\ Be\ aware\ that\ the\ output\ length\ grows\ factorially,\ so\ a\ 7-element\ input\nproduces\ over\ 5000\ permutations...\n\n======\nproc\ lpermute\ L\ \{\n\ \ \ \ if\ \{\[llength\ \$L\]\ <\ 2\}\ \{\n\ \ \ \ \ \ \ \ set\ res\ \$L\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ pos\ 0\n\ \ \ \ \ \ \ \ foreach\ i\ \$L\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ rest\ \[lreplace\ \$L\ \$pos\ \$pos\]\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ pos\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ j\ \[lpermute\ \$rest\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ res\ \[concat\ \[list\ \$i\]\ \$j\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ res\n\}\ \;#\ RS\n======\n\n''Find\ the\ list\ element\ numerically\ closest\ to\ a\ given\ value'''\n\n\[\[F\]or\ a\ given\ value,\ find\ one\ element\ from\ a\ given\ list\ with\ minimal\ absolute\ndifference\ \[\[...\]\n\n======\nproc\ closest\ \{value\ list\}\ \{\n\ \ \ \ set\ minElement\ \[lindex\ \$list\ 0\]\n\ \ \ \ set\ minDist\ \[expr\ \{abs(\$value-\$minElement)\}\]\n\ \ \ \ foreach\ i\ \[lrange\ \$list\ 1\ end\]\ \{\n\ \ \ \ \ \ \ if\ \{abs(\$value-\$i)\ <\ \$minDist\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ set\ minDist\ \[expr\ \{abs(\$value-\$i)\}\]\n\ \ \ \ \ \ \ \ \ \ \ set\ minElement\ \$i\n\ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ minElement\n\}\nIn\ borderline\ cases,\ it\ picks\ the\ first\ hit,\ though:\n%\ closest\ \ 2.5\ \{1\ 2\ 3\ 4\ 5\}\n2\n======\n\n----\n\n'''Compact\ an\ integer\ list:'''\ merge\ consecutive\ numbers,\ if\ more\ than\ two,\ninto\ a\ dash-separated\ range\ (an\ extra\ element\ is\ appended\ to\ the\ list\ to\ncollect\ the\ final\ buffer):\n\n======\nproc\ rangify\ list\ \{\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ set\ buf\ \{\}\n\ \ \ \ foreach\ i\ \[lappend\ list\ \{\}\]\ \{\n\ \ \ \ \ \ \ \ if\ \{\$buf\ eq\ \{\}\ ||\ \$i\ ==\ \[lindex\ \$buf\ end\]\ +\ 1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ buf\ \$i\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[llength\ \$buf\]\ >\ 2\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ buf\ \[lindex\ \$buf\ 0\]-\[lindex\ \$buf\ end\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ res\ \$buf\n\ \ \ \ \ \ \ \ \ \ \ \ set\ buf\ \$i\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ join\ \$res\n\}\ \;#RS\n======\n\n======none\n%\ rangify\ \{1\ 2\ 3\ 5\ 6\ 7\ 9\ 10\ 12\ 13\ 14\ 17\ 18\ 19\}\n1-3\ 5-7\ 9\ 10\ 12-14\ 17-19\n======\n\nHere's\ an\ alternative\ remake\ of\ October\ 2005,\ with\ an\ expander,\ too:\n\n======\nproc\ compress\ list\ \{\ \n\ \ \ \ set\ res\ \[lindex\ \$list\ 0\]\ \n\ \ \ \ for\ \{set\ i\ 1\}\ \{\$i\ <\ \[llength\ \$list\]\ -\ 1\}\ \{incr\ i\}\ \{\ \n\ \ \ \ \ \ \ set\ it\ \[lindex\ \$list\ \$i\]\ \n\ \ \ \ \ \ \ if\ \{\$it\ ==\ \[lindex\ \$list\ \[expr\ \{\$i-1\}\]\]\ +\ 1\ \n\ \ \ \ \ \ \ \ \ \ \ &&\ \$it\ ==\ \[lindex\ \$list\ \[expr\ \{\$i+1\}\]\]\ -\ 1\}\ \{\ \n\n\ \ \ \ \ \ \ \ \ \ \ lappend\ res\ -\ \n\ \ \ \ \ \ \ \}\ else\ \{lappend\ res\ \$it\}\ \n\ \ \ \}\ \n\ \ \ lappend\ res\ \[lindex\ \$list\ end\]\ \n\ \ \ regsub\ -all\ --\ \{\ -\ (-\ )*\}\ \$res\ -\ \n\}\n\n#----\ For\ the\ way\ back:\nproc\ expand\ clist\ \{\ \n\ \ \ \ set\ res\ \{\}\ \n\ \ \ \ foreach\ part\ \$clist\ \{\ \n\ \ \ \ \ \ \ \ if\ \[regexp\ \{(\[0-9-\]*\[0-9\])-(.+)\}\ \$part\ ->\ from\ to\]\ \{\ \n\ \ \ \ \ \ \ \ \ \ \ \ while\ \{\$from\ <=\ \$to\}\ \{lappend\ res\ \$from\;\ incr\ from\}\ \n\ \ \ \ \ \ \ \ \}\ else\ \{lappend\ res\ \$part\}\ \n\ \ \ \ \}\ \n\ \ \ \ set\ res\ \n\}\;#\ RS\n======\n\n----\n\n'''List\ constructor:'''\ After\ the\ advent\ of\ multi-index\ \[lindex\]\ and\ \[lset\],\nnested\ lists\ can\ conveniently\ be\ used\ e.g.\ for\ matrixes,\ but\ all\ list\ elements\nmust\ be\ present\ for\ them\ to\ work.\ Here's\ a\ nestable\ constructor\ that\ fills\ a\nlist\ with\ the\ specified\ initial\ value:\n\n======\nproc\ lrepeat\ \{value\ number\}\ \{\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i<\$number\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ lappend\ res\ \$value\n\ \ \ \ \}\n\ \ \ \ set\ res\n\}\ \;#\ RS\n%\ lrepeat\ foo\ 5\nfoo\ foo\ foo\ foo\ foo\n%\ lrepeat\ \[lrepeat\ 0\ 5\]\ 5\n\{0\ 0\ 0\ 0\ 0\}\ \{0\ 0\ 0\ 0\ 0\}\ \{0\ 0\ 0\ 0\ 0\}\ \{0\ 0\ 0\ 0\ 0\}\ \{0\ 0\ 0\ 0\ 0\}\n======\n\nThe\ second\ edition\ saves\ you\ the\ nesting,\ accepts\ indices\ in\ a\ list\ or\nseparately,\ just\ like\ lset\ or\ lindex:\n\n======\nproc\ lrepeat\ \{value\ args\}\ \{\n\ \ \ \ if\ \{\[llength\ \$args\]\ ==\ 1\}\ \{set\ args\ \[lindex\ \$args\ 0\]\}\n\ \ \ \ foreach\ number\ \$args\ \{\n\ \ \ \ \ \ \ incr\ number\ 0\ \;#\ force\ integer\ (1)\n\ \ \ \ \ \ \ set\ buf\ \{\}\n\ \ \ \ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$number\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ lappend\ buf\ \$value\n\ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ set\ value\ \$buf\n\ \ \ \ \}\n\ \ \ \ set\ buf\n\}\n%\ lrepeat\ \ 0\ 3\ 4\n\{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\n%\ lrepeat\ \ 0\ \{3\ 4\}\n\{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\n%\ lrepeat\ \ 0\ \{3\ 4\ 5\}\n\{\{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\}\ \{\{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\}\ \{\{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\}\ \{\{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\}\ \{\{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\ \{0\ 0\ 0\}\}\n======\n\n(1):\ See\ \[Stress\ testing\]\ for\ why\ this\ makes\ the\ code\ safer.\n\n\[DKF\]:\ Tcl\ 8.5a0\ has\ a\ variation\ on\ this\ which\ behaves\ like\ this:\n\n======\nproc\ lrepeat\ \{count\ value\ args\}\ \{\n\ \ \ \ set\ values\ \[linsert\ \$args\ 0\ \$value\]\n\ \ \ \ set\ result\ \{\}\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$count\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ eval\ \[list\ lappend\ result\]\ \$values\n\ \ \ \ \}\n\ \ \ \ return\ \$result\n\}\n======\n\nAnd\ now,\ because\ I\ can't\ resist\ it,\ here's\ an\ even\ hackier\ way\ to\ do\ it.\ \ :^D\n\n======\nproc\ lrepeat\ \{count\ args\}\ \{\n\ \ \ \ set\ result\ \{\}\n\ \ \ \ set\ cmd\ \[list\ eval\ \[list\ lappend\ result\]\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$count\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ lappend\ cmd\ \$args\n\ \ \ \ \}\n\ \ \ \ eval\ \$cmd\n\}\n======\n\n\[AMG\]:\ This\ second\ version\ is\ the\ more\ efficient\ of\ the\ two.\ \ It\ is\ also\ more\ correct\ in\ that\ it\ allows\ \[\[\[lrepeat\]\]\]\ to\ take\ only\ one\ argument\ (the\ count),\ in\ which\ case\ it\ returns\ empty\ string.\ \ Though\ to\ be\ pedantic,\ both\ are\ technically\ incorrect\ for\ Tcl\ 8.5a0\ which\ predates\ TIP\ 323\ \[http://tip.tcl.tk/323\]\;\ back\ then,\ \[\[lrepeat\]\]\ arbitrarily\ rejected\ \$count\ =\ 0.\n\n\[FW\]:\ Here's\ a\ most\ minimalist\ way\ (and\ of\ course\ the\ less\ efficient).\n\n======\nproc\ lrepeat\ \{count\ args\}\ \{string\ repeat\ \"\$args\ \"\ \$count\}\n======\n\n\[AMG\]:\ \[DKF\]'s\ \"efficient\"\ version\ does\ far\ more\ work\ than\ it\ has\ to.\ \ Here's\ a\ significantly\ faster\ approach:\n\n======\nproc\ lrepeat\ \{count\ args\}\ \{\n\ \ \ \ set\ cmd\ \[list\ concat\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$count\}\ \{incr\ i\}\ \{\n\ \ \ \ \ \ \ lappend\ cmd\ \$args\n\ \ \ \ \}\n\ \ \ \ eval\ \$cmd\n\}\n======\n\nAnd\ another\ version\ with\ a\ slightly\ faster\ loop:\n\n======\nproc\ lrepeat\ \{count\ args\}\ \{\n\ \ \ \ set\ cmd\ \[list\ concat\]\n\ \ \ \ incr\ count\n\ \ \ \ while\ \{\[incr\ count\ -1\]\}\ \{\n\ \ \ \ \ \ \ \ lappend\ cmd\ \$args\n\ \ \ \ \}\n\ \ \ \ eval\ \$cmd\n\}\n======\n\nTiming:\n\n======\n%\ info\ patchlevel\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \;#\ 8.6.1\n%\ time\ \{dkf_1\ \ \ 123\ x\ y\ z\}\ 10000\ \ \;#\ 773.3324\ microseconds\ per\ iteration\n%\ time\ \{dkf_2\ \ \ 123\ x\ y\ z\}\ 10000\ \ \;#\ 108.0783\ microseconds\ per\ iteration\n%\ time\ \{amg_1\ \ \ 123\ x\ y\ z\}\ 10000\ \ \;#\ \ 27.1447\ microseconds\ per\ iteration\n%\ time\ \{amg_2\ \ \ 123\ x\ y\ z\}\ 10000\ \ \;#\ \ 21.9983\ microseconds\ per\ iteration\n%\ time\ \{lrepeat\ 123\ x\ y\ z\}\ 10000\ \ \;#\ \ \ 3.5693\ microseconds\ per\ iteration\n======\n\nAnd\ for\ a\ laugh,\ here's\ the\ time\ for\ \[FW\]'s\ less\ efficient\ approach:\n\n======\n%\ time\ \{fw_1\ \ \ \ 123\ x\ y\ z\}\ 10000\ \ \;#\ \ \ 2.4697\ microseconds\ per\ iteration\n======\n\nYup.\ \ It's\ faster\ than\ the\ native\ \[\[lrepeat\]\]!\ \ But\ the\ return\ value\ is\ subtly\ different.\ \ Let's\ make\ it\ fair:\n\n======\n%\ proc\ fw_2\ \{count\ args\}\ \{linsert\ \[string\ repeat\ \"\$args\ \"\ \$count\]\ 0\}\n%\ time\ \{fw_2\ \ \ \ 123\ x\ y\ z\}\ 10000\ \ \;#\ \ 60.4778\ microseconds\ per\ iteration\n======\n\nThis\ version\ forces\ its\ result\ to\ be\ a\ pure\ list.\ \ And\ wow,\ despite\ being\ \"less\ efficient\",\ \[FW\]'s\ dalliance\ with\ strings\ is\ still\ faster\ than\ any\ of\ the\ list\ manipulation\ approaches\ that\ had\ preceded\ it.\ \ That's\ quite\ impressive.\ \ I\ believe\ the\ reason\ is\ that\ it\ avoids\ \[\[\[eval\]\]\]\ and\ all\ Tcl-based\ looping.\ \ It's\ just\ two\ commands,\ and\ almost\ no\ work\ is\ done\ in\ \[TEBC\].\n\n----\n'''List\ equality\ test'''\ independent\ of\ whitespace\ outside\ of\ elements:\ Taken\ from\ \[A\ little\ XML\ parser\]\ where\ you\ can\ find\ other\ things\ to\ do\ with\ lists\n\n======\nproc\ lequal\ \{a\ b\}\ \{\n\ \ \ \ if\ \{\[llength\ \$a\]\ !=\ \[llength\ \$b\]\}\ \{return\ 0\}\n\ \ \ \ if\ \{\[lindex\ \$a\ 0\]\ ==\ \$a\}\ \{return\ \[string\ equal\ \$a\ \$b\]\}\n\ \ \ \ foreach\ i\ \$a\ j\ \$b\ \{if\ \{!\[lequal\ \$i\ \$j\]\}\ \{return\ 0\}\}\n\ \ \ \ return\ 1\n\}\ \;#\ RS\n======\n\n\[HaO\]\ 2014-09-16:\ \[aspect\]\ proposed\ on\ the\ chat:\n======tcl\n\[list\ \{*\}\$l1\]\ eq\ \[list\ \{*\}\$l2\]\n======\n\n'''Check\ if\ combination\ of\ list\ elements\ is\ valid'''\ against\ a\ list\ of\ lists,\n\n\[JM\]\ 2004-01-04:\ \ this\ code\ relies\ on\ 'lequal'\n\n======\nset\ thisCase\ \[list\ a\ c\ b\]\n\nset\ lstValid\ \{\n\ \ \ \ \{a\ b\ c\}\n\ \ \ \ \{a\ a\ c\}\n\ \ \ \ \{a\ b\ b\}\n\ \ \ \ \{a\ a\ a\}\n\}\n======\n\n======\nproc\ chkValidCombination\ \{lstValid\ thisCase\}\ \{\n\ \ \ \ set\ valid\ 0\n\ \ \ \ foreach\ validCase\ \$lstValid\ \{\n\ \ \ \ \ \ \ \ set\ equal\ \[lequal\ \$validCase\ \$thisCase\]\n\ \ \ \ \ \ \ \ if\ \{\$equal\}\ \{set\ valid\ 1\}\n\ \ \ \ \}\n\n\ \ \ \ return\ \$valid\n\}\n\nputs\ \[chkValidCombination\ \$lstValid\ \$thisCase\]\n======\n\n----\n\n'''Keylist\ access:'''\ Data\ arranged\ as\ alternating\ ''key\ value''...\ can\ be\nsearched\ like\ this,\ where\ non-existing\ keys\ just\ return\ an\ empty\ list:\n\n======\nproc\ keyget\ \{list\ key\}\ \{\n\ \ \ \ foreach\ \{lkey\ value\}\ \$list\ \{\n\ \ \ \ \ \ \ \ if\ \[string\ equal\ \$lkey\ \$key\]\ \{return\ \$value\}\n\ \ \ \ \}\n\}\ \;#\ RS\n%\ keyget\ \{fnm\ John\ lnm\ Brown\ phone\ (123)456-7890\ email\ [email protected]\}\ phone\n(123)456-7890\n%\ keyget\ \{fnm\ John\ lnm\ Brown\ phone\ (123)456-7890\ email\ [email protected]\}\ fax\n======\n\n----\n\n'''Insert\ element\ into\ sorted\ list'''\ at\ suitable\ position:\n\n======\nproc\ linsertsorted\ \{list\ newElement\}\ \{\n\ \ \ \ set\ pos\ 0\n\ \ \ \ foreach\ element\ \$list\ \{\n\ \ \ \ \ \ \ \ if\ \{\$element\ >\ \$newElement\}\ break\n\ \ \ \ \ \ \ \ incr\ pos\n\ \ \ \ \}\n\ \ \ \ linsert\ \$list\ \$pos\ \$newElement\n\}\ \;#\ RS\ --\ testing:\n======\n======none\n%\ linsertsorted\ \{a\ b\ c\ d\ e\}\ f\na\ b\ c\ d\ e\ f\n%\ linsertsorted\ \{a\ b\ c\ d\ e\}\ 0\n0\ a\ b\ c\ d\ e\n%\ linsertsorted\ \{a\ b\ c\ d\ e\}\ aa\na\ aa\ b\ c\ d\ e\n======\n\n\[DKF\]\ notes\ that\ this\ is\ the\ most\ efficient\ way\ to\ maintain\ a\ sorted\ list\ of\nthings\ with\ occasional\ insertions\ of\ elements.\ \ The\ alternative\ -\ append\ and\nfull\ resort\ -\ is\ much\ more\ costly\ as\ the\ list\ size\ increases.\n\n\[jcw\]\ 2004-10-04:\ \ Let\ me\ split\ hairs\ here.\ \ What\ you\ end\ up\ with\ is\ \"insertion\nsort\",\ not\ the\ most\ efficient\ sort\ algorithm\ in\ the\ world.\ \ For\ single,\nincidental\ inserts:\ yes,\ good\ approach.\ \ But\ if\ the\ insertions\ come\ in\ bursts,\nit's\ not\ optimal.\ \ One\ could\ collect\ insertions,\ and\ resort\ lazily\ on\ first\naccess.\ \ Implementation\ left\ as\ exercise\ for\ the\ reader\ (heh!).\n\n\[AF\]:\ \ here\ is\ my\ implementation\ of\ a\ BINARY\ insertion\ sort:\n\n======\nproc\ BinaryInsert\ \{list\ pattern\}\ \{\n\ \ \ \ set\ lo\ -1\n\ \ \ \ set\ hi\ \[llength\ \$list\]\n\ \ \ \ set\ test\ \[expr\ \{\$hi\ /\ 2\}\]\n\ \ \ \ while\ \{\$lo\ !=\ \$test\}\ \{\n\ \ \ \ \ \ \ \ set\ res\ \[string\ compare\ -nocase\ \[lindex\ \$list\ \$test\]\ \$pattern\]\n\ \ \ \ \ \ \ \ if\ \{\$res\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ lo\ \$test\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\$res\ >\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ hi\ \$test\n\ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ \[linsert\ \$list\ \$test\ \$pattern\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ set\ test\ \[expr\ \{(\$hi\ +\ \$lo)\ /\ 2\}\]\n\ \ \ \ \}\n\ \ \ \ return\ \[linsert\ \$list\ \$hi\ \$pattern\]\n\}\n======\n\n----\n\n'''Swap\ a\ paired\ list''':\ e.g.\ dictionaries,\ string\ maps,\ x/y\ coordinates...\n\n======\nproc\ lswap\ list\ \{\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ foreach\ \{a\ b\}\ \$list\ \{lappend\ res\ \$b\ \$a\}\n\ \ \ \ set\ res\n\}\ \;#\ RS\n%\ lswap\ \{a\ b\ c\ d\ e\ f\ g\ h\}\nb\ a\ d\ c\ f\ e\ h\ g\n======\n\n----\n\n'''List\ intersection:'''\ For\ a\ number\ of\ lists,\ return\ only\ those\ elements\ that\nare\ present\ in\ all\ lists:\n\n======\nproc\ intersect\ args\ \{\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ \ \ \ \ foreach\ element\ \[lindex\ \$args\ 0\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ foreach\ list\ \[lrange\ \$args\ 1\ end\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[lsearch\ -exact\ \$list\ \$element\]\ <\ 0\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ found\ 0\;\ break\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$found\}\ \{lappend\ res\ \$element\}\n\ \ \ \ \ \}\n\ \ \ \ \ set\ res\n\}\ \;#\ RS\n======\n\[kpv\]\ 2018-10-24:\ here's\ a\ one-liner\ using\ \[lmap\]\ for\ intersecting\ two\ lists:\n======\nset\ intersect\ \[lmap\ a\ \$alist\ \{if\ \{\$a\ in\ \$blist\}\ \{set\ a\}\ else\ continue\}\]\n======\n\[RS\]\ 2015-05-13:\ a\ simpler\ take\ for\ two\ lists,\ using\ the\ \[in\]\ operator:\n======\n\n\}\n======\n\n\[RKzn\]\ 2016-09-28:\ the\ previous\ proc\ works\ provided\ the\ first\ list\ does\ not\ have\ duplicate\ elements.\ Otherwise\ all\ elements\ from\ the\ first\ list\ that\ match\ at\ least\ one\ element\ from\ the\ second\ list\ will\ be\ included\ in\ the\ result:\n\n======\ntcl>\ lintersect\ \{a\ b\}\ \{a\ c\}\na\ntcl>\ lintersect\ \{a\ a\ b\}\ \{a\ c\}\na\ a\n======\n\nBy\ the\ way,\ lists\ without\ duplicates\ (or\ ignoring\ the\ ones\ that\ may\ exist)\ can\ be\ seen\ as\ sets.\ For\ those,\ there\ are\ implementations\ for\ intersection\ in\ \[tcllib\]:\ '::\[struct::set\]\ intersect'\ and\ '::struct::set\ intersect3'\n\n\n\ \ \ inList2:\ \ \ Name\ of\ the\ list\ in\ which\ to\ put\ list2\ only\ elements\n\n\ \ \ inBoth:\ \ \ Name\ of\ the\ list\ in\ which\ to\ put\ elements\ in\ list1\ &\ list2\n\n======\nproc\ intersect3\ \{list1\ list2\ inList1\ inList2\ inBoth\}\ \{\n\ \ \ \ upvar\ \$inList1\ in1\n\ \ \ \ upvar\ \$inList2\ in2\n\ \ \ \ upvar\ \$inBoth\ \ inB\n\n\ \ \ \ set\ in1\ \[list\]\n\ \ \ \ set\ in2\ \[list\]\n\ \ \ \ set\ inB\ \[list\]\n\n\ \ \ \ set\ list1\ \[lsort\ \$list1\]\n\ \ \ \ set\ list2\ \[lsort\ \$list2\]\n\n\ \ \ \ #\ Shortcut\ for\ identical\ lists\ is\ faster\n\ \ \ \ if\ \{\ \$list1\ ==\ \$list2\ \}\ \{\ \ \ \n\ \ \ \ \ \ \ \ set\ inB\ \$list1\n\ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ set\ i\ 0\n\ \ \ \ \ \ \ \ foreach\ element\ \$list1\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[set\ p\ \[lsearch\ \[lrange\ \$list2\ \$i\ end\]\ \$element\]\]\ ==\ -1\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ in1\ \$element\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\ \$p\ >\ 0\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ e\ \[expr\ \{\$i\ +\ \$p\ -1\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ foreach\ entry\ \[lrange\ \$list2\ \$i\ \$e\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ in2\ \$entry\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ i\ \$p\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ incr\ i\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ inB\ \$element\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ foreach\ entry\ \[lrange\ \$list2\ \$i\ end\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ in2\ \$entry\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\ \;#\ David\ Easton\n======\n\n----\n\n'''Prepend\ elements\ to\ a\ list'''\ (add\ in\ front):\n\n======\nproc\ lprepend\ \{var\ args\}\ \{\n\ \ \ \ upvar\ 1\ \$var\ v\n\ \ \ \ set\ v\ \[eval\ \[list\ linsert\ \$v\ 0\]\ \$args\]\n\}\ \;#\ DKF\n======\n\n\[TR\]:\ \ You\ can\ also\ use\ `\[lreplace\]`\ where\ the\ first\ index\ is\ -1\ and\ the\ second\nis\ -2\ ...\ like\ so:\n\n======\nset\ myList\ \[list\ 0\ 1\ 2\]\nset\ myList\ \[lreplace\ \$myList\ -1\ -2\ 5\]\n#->\ 5\ 0\ 1\ 2\n======\n\n----\n\n\[GPS\]\ 2003:\ \ In\ the\ \[Tcl\ Chatroom\]\ I\ came\ up\ with\ this\ idea.\ \ You\ may\ find\ it\neasier\ than\ using\ lreplace\ to\ do\ the\ same.\n\n======\nproc\ remove.list.item\ \{lPtr\ i\}\ \{\n\ \ \ \ upvar\ \$lPtr\ l\;\ set\ l\ \[lreplace\ \$l\ \$i\ \$i\]\n\}\n======\n\nExample:\n\n======none\n%\ set\ l\ \[list\ a\ b\ c\]\ \na\ b\ c\n%\ remove.list.item\ l\ 1\na\ c\n%\ set\ l\na\ c\n======\n\n----\n\n'''Key-value\ list\ searching''':\ Before\ \[dict\]\ arrived,\ we\ could\ have\ a\ two-way\nmap\ key<->value\ like\ this:\n\n======\nproc\ kvsearch\ \{kvlist\ item\}\ \{\n\ \ \ \ set\ pos\ \[lsearch\ \$kvlist\ \$item\]\n\ \ \ \ if\ \{\$pos\ !=\ -1\}\ \{\n\ \ \ \ \ \ \ \ lindex\ \$kvlist\ \[expr\ \{\$pos+1-2*(\$pos%2)\}\]\n\ \ \ \ \}\n\}\ \;#\ RS\n%\ kvsearch\ \{1\ one\ 2\ two\ 3\ three\}\ four\ \;#\ returns\ empty\ string/list\n%\ kvsearch\ \{1\ one\ 2\ two\ 3\ three\}\ 1\none\n0\ %\ kvsearch\ \{1\ one\ 2\ two\ 3\ three\}\ one\n1\n======\n\n----\n\n'''Pairs'''\ of\ members\ of\ a\ list:\n\n======\nproc\ pairs\ set\ \{\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ set\ last\ \[expr\ \{\[llength\ \$set\]-1\}\]\n\ \ \ \ for\ \{set\ ia\ 0\}\ \{\$ia\ <\ \$last\}\ \{incr\ ia\}\ \{\n\ \ \ \ \ \ \ \ foreach\ b\ \[lrange\ \$set\ \[expr\ \{\$ia+1\}\]\ end\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ res\ \[list\ \[lindex\ \$set\ \$ia\]\ \$b\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ set\ res\n\}\ \;#\ RS\n%\ pairs\ \{a\ b\ c\ d\}\n\{a\ b\}\ \{a\ c\}\ \{a\ d\}\ \{b\ c\}\ \{b\ d\}\ \{c\ d\}\n======\n\nSimpler:\n\n======\nproc\ pairs\ set\ \{\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ foreach\ a\ \[lrange\ \$set\ 0\ end-1\]\ \{\n\ \ \ \ \ \ \ \ set\ set\ \[lrange\ \$set\ 1\ end\]\n\ \ \ \ \ \ \ \ foreach\ b\ \$set\ \{lappend\ res\ \[list\ \$a\ \$b\]\}\n\ \ \ \ \}\n\ \ \ \ set\ res\n\}\ \;#\ RS\n======\n\n\n----\n\n'''In-place\ queues'''\ using\ the\ \[K\]\ combinator\n\n======\nproc\ K\ \{a\ b\}\ \{set\ a\}\n##\n#\ Pop\ an\ item\ off\ a\ list,\ left\ or\ right\n#\nproc\ lpop\ \{how\ listName\}\ \{\n\ \ \ \ upvar\ \$listName\ list\n\ \ \ \ switch\ --\ \$how\ \{\n\ \ \ \ \ \ \ \ right\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ K\ \[lindex\ \$list\ end\]\ \[set\ list\ \[lrange\ \$list\ 0\ end-1\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ left\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ K\ \[lindex\ \$list\ 0\]\ \[set\ list\ \[lrange\ \$list\ 1\ end\]\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \{lpop\ right|left\ listName\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n##\n#\ Pop\ an\ item\ onto\ a\ list,\ left\ or\ right\n#\nproc\ lpush\ \{how\ listName\ item\}\ \{\n\ \ \ \ upvar\ \$listName\ list\n\ \ \ \ switch\ --\ \$how\ \{\n\ \ \ \ \ \ \ \ right\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ list\ \$item\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ left\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ list\ \[linsert\ \[K\ \$list\ \[set\ list\ \{\}\]\]\ 0\ \$item\]\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -code\ error\ \"lpush\ right|left\ listName\ item\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\}\n======\n\nSee\ also\ \[Stacks\ and\ queues\],\ \[Implementing\ FIFO\ queues\]\ and\ \[Tcllib\]'s\ \[stack\]\nand\ \[queue\].\n\n----\n\n'''Flatten\ a\ list'''\ of\ any\ depth,\ i.e.\ remove\ all\ grouping:\n\nUse\ `\[\[::struct::list\ flatten\]`\ in\ \[tcllib\]\n\n======\n::struct::list\ flatten\ ?-full?\ ?--?\ sequence\n======\n\nThe\ subcommand\ takes\ a\ single\ sequence\ and\ returns\ a\ new\ sequence\ where\ one\ level\ of\ nesting\ was\ removed\ from\ the\ input\ sequence.\ In\ other\ words,\ the\ sublists\ in\ the\ input\ sequence\ are\ replaced\ by\ their\ elements.\n\nThe\ subcommand\ will\ remove\ any\ nesting\ it\ finds\ if\ the\ option\ -full\ is\nspecified.\n\n======none\n%\ ::struct::list\ flatten\ \{1\ 2\ 3\ \{4\ 5\}\ \{6\ 7\}\ \{\{8\ 9\}\}\ 10\}\n1\ 2\ 3\ 4\ 5\ 6\ 7\ \{8\ 9\}\ 10\n%\ ::struct::list\ flatten\ -full\ \{1\ 2\ 3\ \{4\ 5\}\ \{6\ 7\}\ \{\{8\ 9\}\}\ 10\}\n1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ 10\n======\n\nBut\ note\ that\ it\ may\ be\ inconsistent\ or\ otherwise\ counterintuitive:\n======\n%\ ::struct::list\ flatten\ -full\ \{1\ 2\ 3\ \{4\ 5\}\ \{6\ 7\}\ \{\{8\ 9\}\}\ 10\}\n1\ 2\ 3\ 4\ 5\ 6\ 7\ 8\ 9\ 10\n%\ ::struct::list\ flatten\ -full\ \{1\ 2\ 3\{4\ 5\}\ \{6\ 7\}\ \{\{8\ 9\}\}\ 10\}\n1\ 2\ 3\\\{4\ 5\\\}\ 6\ 7\ 8\ 9\ 10\n%\ ::struct::list\ flatten\ -full\ \{1\ 2\ 3\ \{4\ 5\}\{6\ 7\}\ \{\{8\ 9\}\}\ 10\}\nlist\ element\ in\ braces\ followed\ by\ \"\{6\"\ instead\ of\ space\n======\nIf\ '''3\\\{4\ 5\\\}'''\ then\ why\ not\ '''\\\{4\ 5\\\}\\\{6\ 7\\\}'''\ or\ even\ '''3\ 4\ 5'''\ and\ '''4\ 5\ 6\ 7'''?\n\nBecause\ `3\{4`\ and\ `5\}`\ are\ syntactically\ valid,\ which\ `\{4\ 5\}\{6`\ isn't\ (the\ closing\ brace\ that\ closes\ the\ initial\ opening\ brace\ isn't\ the\ last\ character\ in\ the\ word).\ `3\{4`\ and\ `5\}`\ can't\ be\ transformed\ into\ `3\ 4\ 5`\ since\ that\ would\ change\ the\ data\ content.\n\n\n\[HaO\]\ 2014-09-16:\ One\ may\ use\ 'concat\ \{*\}'\ to\ flatten\ a\ matrix\ by\ one\ level:\n======tcl\n%\ concat\ \{*\}\{1\ 2\ 3\ \{4\ 5\}\ \{6\ 7\}\ \{\{8\ 9\}\}\ 10\}\n1\ 2\ 3\ 4\ 5\ 6\ 7\ \{8\ 9\}\ 10\n======\n\n----\nIf\ 3\\\{4\ 5\\\}\ then\ why\ not\ \\\{4\ 5\\\}\\\{6\ 7\\\}\ or\ even\ 3\ 4\ 5\ and\ 4\ 5\ 6\ 7?\n\[MAK\]:\ \ Perhaps\ belongs\ in\ \[Additional\ string\ functions\],\ but:\nThis\ function\ takes\ a\ list\ of\ lists\ representing\ cell\ information\ for\ a\ table\n(i.e.,\ each\ element\ of\ the\ top-level\ list\ is\ a\ row\ of\ data,\ and\ each\ element\ of\nthose\ are\ individual\ columns\ of\ data)\ and\ generates\ text\ output\ with\ all\ of\ the\ncolumns\ aligned\ with\ each\ other.\ \ By\ default\ a\ single\ space\ is\ output\ between\nthe\ longest\ cell\ and\ the\ next\ one\;\ extra\ spaces\ can\ be\ added\ through\ the\noptional\ padding\ argument.\n\n======\nproc\ listToTable\ \{\ in\ \{padding\ 0\}\ \}\ \{\n\ \ \ \ set\ result\ \{\}\n\ \ \ \ array\ set\ lengths\ \{\}\n\ \ \ \ #\ Determine\ the\ longest\ element\ in\ each\ column\n\ \ \ \ foreach\ line\ \$in\ \{\n\ \ \ \ \ \ \ \ set\ colnum\ 1\n\ \ \ \ \ \ \ \ foreach\ column\ \$line\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ length\ \[string\ length\ \$column\]\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\[info\ exist\ lengths(\$colnum)\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$lengths(\$colnum)\ <\ \$length\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lengths(\$colnum)\ \$length\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ lengths(\$colnum)\ \$length\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ colnum\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\n\ \ \ \ #\ Format\ the\ output\n\ \ \ \ foreach\ line\ \$in\ \{\n\ \ \ \ \ \ \ \ set\ colnum\ 1\n\ \ \ \ \ \ \ \ set\ maxcol\ \[llength\ \$line\]\n\ \ \ \ \ \ \ \ foreach\ column\ \$line\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$colnum\ <\ \$maxcol\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ format\ %-*s\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ expr\ \{\$lengths(\$colnum)\ +\ 1\ +\ \$padding\}\]\ \$column\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ append\ result\ \$column\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ incr\ colnum\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ append\ result\ \"\\n\"\n\ \ \ \ \}\n\ \ \ \ return\ \$result\n\}\n======\n\nExample:\n\n======none\n%\ listToTable\ \{a\ \{aaaa\ bb\ cccccc\}\ \{aaaaaa\ bbbbbbb\ cc\ ddddddd\}\ \{a\ b\ c\ d\}\}\na\naaaa\ \ \ bb\ \ \ \ \ \ cccccc\naaaaaa\ bbbbbbb\ cc\ \ \ \ \ ddddddd\na\ \ \ \ \ \ b\ \ \ \ \ \ \ c\ \ \ \ \ \ d\n======\n\n----\n\n\[AMG\]:\ \ \[interleave\]\ lets\ you\ combine\ parallel\ lists\ so\ you\ can\ pass\ them\ to\n\[\[array\ set\]\].\ \ \[\[listc\]\]\ and\ \[\[\[lcomp\]\]\]\ provide\ \[list\ comprehension\]s.\n\n----\n\n\[Sarnold\]:\ \ A\ command\ for\ '''splitting\ one\ list\ into\ segments'''\n\nInstead\ of\ doing:\n\n======\nset\ beginning\ \[lrange\ \$list\ 0\ end-\$size\]\nset\ end\ \[lrange\ \$list\ end-\[expr\ \{\$size-1\}\]\ end\]\n======\n\nwrite\ more\ understandable\ things\ like:\n\n======\nforeach\ \{beginning\ end\}\ \[lrange\ -split\ \$list\ end-\$size\]\ \{break\}\n======\n\nOf\ course,\ it\ may\ be\ implemented\ in\ pure\ tcl...\n\n----\n\nOk,\ so\ I'd\ propose\ also\ my\ extensions.\n\n'''Selects\ elements\ of\ a\ list\ on\ given\ positions\ and\ return\ them\ as\ a\ list'''.\n\n======none\n%set\ a\ \{one\ two\ three\ four\ five\}\n...\n%lselect\ \$a\ 0\ 3-4\none\ four\ five\n======\n\n======\nproc\ lselect\ \{list\ args\}\ \{\n\ \ \ \ set\ result\ \{\}\n\n\ \ \ \ foreach\ i\ \$args\ \{\n\ \ \ \ \ \ \ \ set\ range\ \[split\ \$i\ -\]\n\ \ \ \ \ \ \ \ if\ \{\ \[llength\ \$range\]\ ==\ 2\ \}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ mset\ \{from\ to\}\ \$range\n\ \ \ \ \ \ \ \ \ \ \ \ for\ \{set\ n\ \$from\}\ \{\$n\ <=\ \$to\}\ \{incr\ n\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ result\ \[lindex\ \$list\ \$n\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \ \ \ \ continue\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ lappend\ result\ \[lindex\ \$list\ \$i\]\n\ \ \ \ \}\n\ \ \ \ return\ \$result\n\}\n======\n\n'''Splitting\ list\ at\ index:'''\n\n======\nproc\ lsplit\ \{ls\ index\}\ \{\n\ \ \ \ return\ \[\n\ \ \ \ \ \ \ \ list\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ lrange\ \$ls\ 0\ \[expr\ \{\$index-1\}\]\]\ \[\n\ \ \ \ \ \ \ \ \ \ \ \ lrange\ \$ls\ \$index\ end\]\]\n\}\n======\n\nFunctional\ extensions:\n\n'''Filter\ each\ element\ through\ given\ command\ and\ return\ them\ as\ a\ list:'''\n\n======\nproc\ filter\ \{list\ cmd\}\ \{\n\ \ \ \ set\ result\ \{\}\n\ \ \ \ foreach\ i\ \$list\ \{\n\ \ \ \ \ \ \ \ lappend\ result\ \[eval\ \"\$cmd\ \{\$i\}\"\]\n\ \ \ \ \}\n\ \ \ \ return\ \$result\n\}\n======\n\n======none\n%set\ a\ \{\ \{\ \ \ \ 1\ \}\ \{\ 2\ \ \ \}\ \{\ 3\ \ \ \ \ \}\ \}\n...\n%filter\ \$a\ \"string\ trim\"\n1\ 2\ 3\n======\n\n\[HaO\]\ see\ \[lmap\]\ (new\ in\ tcl8.6)\n\n'''Return\ a\ list\ of\ elements\ that\ satisfy\ given\ predicate:'''\n\n======none\n%\ set\ l\ \{0\ 5\ 3\ 4\ 2\}\n0\ 5\ 3\ 4\ 2\n%\ select\ \$l\ \{expr\ 2<\}\n5\ 3\ 4\n======\n\n======\nproc\ select\ \{list\ pred\}\ \{\n\ \ \ \ set\ result\ \{\}\n\ \ \ \ \n\ \ \ \ foreach\ i\ \$list\ \{\n\ \ \ \ \ \ \ \ if\ \{\[eval\ \$pred\ \[list\ \$i\]\]\}\ \{lappend\ result\ \$i\}\n\ \ \ \ \}\n\ \ \ \ return\ \$result\n\}\n======\n\n\[MG\]\ offers\ an\ alternative\ version,\ that\ uses\ `\[uplevel\]`\ to\ evaluate\ `\$pred`\nin\ the\ caller's\ scope,\ and\ also\ uses\ `\[string\ map\]`\ to\ allow\ the\ value\ being\nchecked\ to\ placed\ anywhere\ in\ it\ (as\ '##')\ -\ it's\ called\ inside\ `\[expr\]`.\ The\nonly\ reason\ it\ uses\ `##`\ as\ the\ placeholder\ for\ the\ value\ is\ because\ I\ couldn't\nthink\ of\ a\ ''good'',\ more\ Tcl'ish\ way\ to\ do\ it,\ and\ that's\ what's\ used\ in\nanother\ language\ I\ use.\ If\ someone\ can\ think\ of\ a\ good\ way\ to\ do\ it\ that\ fits\nmore\ with\ the\ Tcl\ way,\ please\ change\ it.\n\n======\nproc\ select2\ \{list\ pred\}\ \{\n\ \ \ \ set\ result\ \[list\]\n\n\ \ \ \ foreach\ i\ \$list\ \{\n\ \ \ \ \ \ \ \ if\ \{\[uplevel\ 1\ \[list\ expr\ \[string\ map\ \[list\ ##\ \$i\]\ \$pred\]\]\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ result\ \$i\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$result\;\n\}\n======\n\n======none\n%\ set\ list1\ \{a\ b\ c\ d\ e\}\na\ b\ c\ d\ e\n%\ set\ list2\ \{c\ d\ e\ f\ g\}\nc\ d\ e\ f\ g\n%\ select2\ \$list1\ \{\[lsearch\ \$list2\ ##\]>-1\}\nc\ d\ e\n======\n\n\[Lars\ H\]\ thinks\ the\ Tcl\ way\ to\ do\ it\ is\ to\ have\ a\ variable\ that\ contains\ list\nitem\ to\ consider,\ thus:\n\n======\nproc\ select3\ \{var\ expr\ list\}\ \{\n\ \ \ \ upvar\ 1\ \$var\ item\n\ \ \ \ set\ res\ \{\}\n\ \ \ \ foreach\ item\ \$list\ \{\n\ \ \ \ \ \ \ \ if\ \{\[uplevel\ 1\ \[list\ ::expr\ \$expr\]\]\}\ then\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ lappend\ res\ \$item\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$res\n\}\n======\n\nExample:\n\n======none\n%\ select3\ s\ \{\[string\ is\ integer\ \$s\]\}\ \{0\ 3\ x\ 0x3\ 09\ 35\ -7\ 0.\ 000\ 1e3\}\n0\ 3\ 0x3\ 35\ -7\ 000\n%\ select3\ s\ \{\$s\ !=\ 0\}\ \{0\ 3\ x\ 0x3\ 09\ 35\ -7\ 0.\ 000\ 1e3\}\n3\ x\ 0x3\ 09\ 35\ -7\ 1e3\n======\n\nHaving\ the\ list\ last\ makes\ it\ easy\ to\ define\ aliases:\n\n======none\n%\ interp\ alias\ \{\}\ nonzero\ \{\}\ select3\ s\ \{\$s!=0\}\n%\ nonzero\ \{0\ 3\ x\ 0x3\ 09\ 35\ -7\ 0.\ 000\ 1e3\}\n3\ x\ 0x3\ 09\ 35\ -7\ 1e3\n======\n\n\[NEM\]\ 2008-02-17:\ \ \ Would\ call\ the\ `filter`\ above\ `\[map\]`,\ and\ `select`\ would\nbe\ `\[filter\]`.\ I\ agree\ with\ \[Lars\ H\]\ about\ taking\ the\ list\ argument\ last\ (the\n\[tcllib\]\ version\ don't\ do\ this,\ alas).\ As\ an\ example:\n\n======\nproc\ filter\ \{p\ xs\}\ \{\n\ \ \ \ set\ ys\ \[list\]\n\ \ \ \ foreach\ x\ \$xs\ \{if\ \{\[uplevel\ #0\ \$p\ \[list\ \$x\]\]\}\ \{lappend\ ys\ \$x\}\}\n\ \ \ \ return\ \$ys\n\}\n#\ Usage:\nset\ xs\ \{0\ 3\ x\ 0x3\ 09\ 35\ -7\ 0.\ 000\ 1e3\}\nfilter\ \{string\ is\ integer\}\ \$xs\n#\ Simple\ aliases:\nproc\ let\ \{name\ =\ args\}\ \{interp\ alias\ \{\}\ \$name\ \{\}\ \{*\}\$args\}\nlet\ integers\ =\ filter\ \{string\ is\ integer\}\nintegers\ \$xs\ \;#\ Same\ result\n======\n\nMore\ complex\ expressions\ can\ easily\ be\ handled\ by\ \[lambda\]s:\n\n======\nproc\ func\ \{p\ b\}\ \{list\ ::apply\ \[list\ \$p\ \[list\ expr\ \$b\]\]\}\nfilter\ \[func\ x\ \{\$x\ !=\ 0\}\]\ \$xs\n======\n\n----\n\n\[FW\]:\ \ '''A\ more\ versatile\ key-value\ search'''\n\nThis\ function\ allows\ for\ searching\ an\ associative\ `\[dict\]`/`\[array\]`-style\nlist,\ with\ the\ added\ feature\ that\ the\ length\ of\ each\ \"row\"\ can\ be\ anything\n(instead\ of\ just\ 2:\ ''key\ value'')\ and\ you\ can\ pick\ which\ sub-index\ is\ used\ for\nthe\ key\ and\ for\ the\ value\ to\ retrieve.\ \ The\ first\ argument\ is\ the\ list,\ the\nsecond\ is\ the\ key\ to\ search\ for.\ \ Optional\ args:\ the\ third\ (default\ 2)\ is\ the\nlength\ of\ each\ row,\ the\ fourth\ (default\ 0)\ is\ the\ index\ within\ the\ row\ of\ the\nkey,\ and\ the\ fifth\ (default\ 1)\ is\ the\ index\ within\ the\ row\ of\ the\ value\ to\nretrieve.\ \ This\ proc\ requires\ an\ `\[lrepeat\]`\ proc\ (as\ offered\ above\;\ I've\ included\none\ here\ for\ completeness).\n\n======\nproc\ lrepeat\ \{val\ num\}\ \{\n\ \ \ \ set\ res\ \[list\]\n\ \ \ \ for\ \{set\ i\ 0\}\ \{\$i\ <\ \$num\}\ \{incr\ i\}\ \{lappend\ res\ \$val\}\n\ \ \ \ return\ \$res\n\}\n\nproc\ lassoc\ \{list\ key\ \{rowsize\ 2\}\ \{keyind\ 0\}\ \{valind\ 1\}\}\ \{\n\ \ \ \ foreach\ \[lreplace\ \[lreplace\ \[lrepeat\ nullvar\ \$rowsize\]\ \\\n\ \ \ \ \ \ \ \ \$keyind\ \$keyind\ qkey\]\ \$valind\ \$valind\ qval\]\ \$list\ \{\n\ \ \ \ \ \ \ \ if\ \{\[string\ equal\ \$qkey\ \$key\]\}\ \{return\ \$qval\}\n\ \ \ \ \}\n\ \ \ \ return\ -code\ error\ \{No\ match\ found.\}\n\}\n======\n\nExample:\n\n======\n#\ English,\ Dutch,\ French\nset\ phrases\ \[list\ \\\n\ \ \ \ Hi\ Hallo\ Bonjour\ \\\n\ \ \ \ \{I'll\ have\ the\ soup.\}\ \{Ik\ geef\ opdracht\ tot\ de\ soep.\}\ \\\n\ \ \ \ \ \ \ \ \{J'achèterai\ le\ potage\}\ \\\n\ \ \ \ Bye\ \{Tot\ ziens\}\ \{Au\ revoir\}\]\nputs\ \[lassoc\ \$phrases\ Hi\ 3\ 0\ 2\]\ \;#\ English\ to\ French\n======\n\n----\n\n\[Sarnold\]:\ \ I\ would\ like\ to\ filter\ elements\ when\ walking\ a\ list\ with\ `foreach`.\nSomething\ like\ this:\n\n======\nforeach-filter\ x\ \{\$x\ >\ 0\}\ \$list\ \{puts\ \"\$x\ is\ positive\"\}\n======\n\nThis\ improves\ over\ list\ comprehension\ for\ cases\ we\ do\ not\ want\ to\ walk\ the\nwhole\ list.\ (foreach\ is\ lazy)\n\n\[AK\]:\ \ I\ have\ no\ idea\ what\ you\ mean\ by\ 'foreach\ is\ lazy'.\ Can\ you\ elaborate\ ?\n\n`\[struct::list::\]::filterfor`\ is\ very\ similar,\ modulo\ arrangement\nof\ the\ arguments,\ and\ not\ using\ a\ script\ body\n\n\[Sarnold\]:\ \ I\ admit\ I\ abused\ the\ term\ 'lazy'\ but\ I\ meant\ that,\ in\ the\nfollowing:\ \n\n======\nforeach\ x\ \[filter\ \$hugelist\ cmd\]\ \{\n\ \ \ \ if\ \{\[somecmd\ \$x\]\}\ break\n\}\n======\n\nthe\ hugelist\ has\ to\ be\ filtered\ completely\ before\ the\ foreach\ is\ invoked,\nbecause\ of\ Tcl's\ eager\ evaluation.\ \ And\ the\ huge\ list\ is\ transformed\ even\ if\nonly\ one\ item\ is\ processed\ and\ the\ foreach\ loop\ is\ exited\ (via\ break).\ \ But\ the\nsame\ treatment\ could\ be\ optimized\ with\ the\ proposed\ foreach-filter:\n\n======\nforeach-filter\ x\ cmd\ \$hugelist\ \{\n\ \ \ \ if\ \{\[somecmd\ x\]\}\ break\n\}\n======\n\nCompared\ with\ the\ first\ version,\ it\ does\ not\ have\ to\ process\ \$hugelist\ totally,\nlike\ Haskell's\ list\ filters.\ \ (And\ Haskell\ works\ with\ ''lazy''\ evaluation)\ We\ncould\ build\ a\ similar\ foreach-map\ command.\n\n\[AK\]:\ \ Ok,\ now\ I\ understand.\ Both\ Tcl\ using\ 'strict'\ evaluation\ and\ the\ use\ncase\ you\ are\ looking\ for.\ Another\ possibility,\ but\ way\ more\ complex\ for\ the\ninternals\ would\ be\ the\ introduction\ of\ generators.\ Although,\ with\ Tcl\ 8.6's\ncoroutines\ we\ have\ a\ way\ of\ doing\ that\ already.\ Have\ the\ filter\ be\ a\ coroutine\nwhich\ yields\ each\ element\ as\ requested.\ Still,\ foreach\ is\ not\ prepared\ to\ ask\nfor\ elements\ one\ by\ one,\ it\ will\ always\ take\ the\ whole\ list.\ So\ even\ that\ is\nnot\ yet\ a\ workable\ way\ of\ partial\ processing\ of\ a\ computed/infinite\ list.\n\n\[LV\]:\ \ I\ am\ not\ certain,\ but\ would\ the\ \[foreach\ async\]\ discussion\ be\ a\ way\ of\ninteracting\ with\ the\ computed\ infinite\ generated\ lists?\ If\ so,\ then\ is\ this\nperhaps\ something\ that\ could\ appear\ in\ \[tcllib\]'s\ \[control\]\ module\ for\ use\ with\nTcl\ 8.6?\n\n\[MR\]:\ Wouldn't\ following\ suffice\ (unless\ Haskell-like\ /\ generators-like\nsemantics\ are\ really\ required)\ ?\n\n======\nforeach\ x\ \$lst\ \{\n\ \ \ \ if\ \{!\[predicate\ \$x\]\}\ continue\n\ \ \ \ if\ \{whatever\}\ break\n\ \ \ \ we_can_do_whatever_we_want_with\ \$x\ now\n\}\n======\n\nNaive\ implementation\ of\ foreach_filter\ would\ be:\n\n======\nproc\ foreach_filter\ \{varName\ lst\ predicate\ cmd\}\ \{\n\ \ \ \ uplevel\ 1\ \[list\ foreach\ \$varName\ \$lst\ \[list\ if\ \$predicate\ \$cmd\]\]\n\}\n\n======\n\nwhich,\ for\ the\ following\ test\ script:\n\n======\nforeach_filter\ x\ \{aa\ bb\ ab\ ac\}\ \{\[string\ index\ \$x\ 0\]\ ==\ \{a\}\}\ \{\n\ \ \ \ puts\ \$x\n\ \ \ \ if\ \{\$x\ ==\ \{ab\}\}\ break\n\}\n======\n\nyields\ following\ output:\n\n======none\naa\nab\n======\n\nie.\ `bb`\ is\ skipped\ by\ the\ filter\ and\ after\ encountering/printing\ `ab`\ \n`\[break\]`\ kicks\ in\ (hallelujah\ for\ Tcl\ metaprogramming\ !!!\ \;-))\n\n\[YOSIFOV\]:\n\nhttp://balkansoft.blogspot.ru/2012/10/traversing-over-paths.html%|%Original\ is\nhere%|%\n\nWalking\ on\ paths\ (like\ MS-DOS\ paths,\ but\ each\ path\ should\ be\ list\ of\ dirs,\ not\none\ string):\n\n======\nproc\ forpaths\ \{boundVarNames\ paths\ body\}\ \{\n#\ walk\ on\ paths,\ each\ is\ list\ of\ dirs.\ \$body\ will\ execute\ on\ visit\ each\ dir,\n#\ variables\ bound:\n#\ \ \ \$keyName\ -\ current\ path\n#\ \ \ \$levelName\ -\ current\ level\ (0...N)\n#\ \ \ \$leafName\ -\ is\ leaf\ or\ not\ (1,\ 0)\n\ \ \ \ foreach\ \{keyName\ levelName\ leafName\}\ \[lrange\ \$boundVarNames\ 0\ 2\]\ \{\}\n\ \ \ \ set\ group\ \[dict\ create\]\n\ \ \ \ foreach\ path\ \$paths\ \{\n\ \ \ \ \ \ \ \ dict\ set\ group\ \{*\}\$path\ @LEAF\n\ \ \ \ \}\n\n\ \ \ \ proc\ _cmp\ \{a\ b\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\[expr\ \{\$a\ >\ \$b\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ 1\n\ \ \ \ \ \ \ \ \}\ elseif\ \{\[expr\ \{\$a\ <\ \$b\}\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ return\ -1\n\ \ \ \ \ \ \ \ \}\ else\ \{return\ 0\}\n\ \ \ \ \}\n\n\ \ \ \ proc\ _trackpath\ \{track\ level\ dir\}\ \{\n\ \ \ \ \ \ \ \ if\ \{\$track\ eq\ \{\}\}\ \{set\ track\ \[list\ @DUMMY\]\}\n\ \ \ \ \ \ \ \ switch\ --\ \[_cmp\ \[expr\ \$level+1\]\ \[llength\ \$track\]\]\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ 1\ \ \{lappend\ track\ \$dir\n\ \ \ \ \ \ \ \ \ \ \ \ 0\ \ \{lset\ track\ end\ \$dir\}\n\ \ \ \ \ \ \ \ \ \ \ \ -1\ \{set\ track\ \[lreplace\ \$track\ \$level\ end\ \$dir\]\}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ return\ \$track\n\ \ \ \ \}\n\ \ \ \ set\ gtrack\ \{\}\;\ #\ current\ path\ when\ visit\ each\ node\n\n\ \ \ \ proc\ _walk\ \{d\ keyName\ levelName\ leafName\ body\ \{_deep\ 2\}\}\ \{\n\ \ \ \ #\ here\ \$level\ is\ level\ in\ tree,\ not\ in\ stack\n\ \ \ \ #\ \$_deep\ is\ level\ in\ stack\n\ \ \ \ \ \ \ \ upvar\ \$_deep\ \$keyName\ key\ \$levelName\ level\n\ \ \ \ \ \ \ \ upvar\ gtrack\ gtrack\n\ \ \ \ \ \ \ \ if\ \{\$leafName\ ne\ \{\}\}\ \{\ upvar\ \$_deep\ \$leafName\ leaf\ \}\n\ \ \ \ \ \ \ \ dict\ for\ \{k\ v\}\ \$d\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ set\ level\ \[expr\ \{\$_deep-2\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ gtrack\ \[_trackpath\ \$gtrack\ \$level\ \$k\]\n\ \ \ \ \ \ \ \ \ \ \ \ set\ key\ \$gtrack\n\ \ \ \ \ \ \ \ \ \ \ \ if\ \{\$v\ eq\ @LEAF\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leaf\ 1\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uplevel\ \$_deep\ \$body\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ #\ nested\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ set\ leaf\ 0\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ uplevel\ \$_deep\ \$body\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ _walk\ \$v\ \$keyName\ \$levelName\ \$leafName\ \$body\ \[expr\ \{\$_deep+1\}\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ _walk\ \$group\ \$keyName\ \$levelName\ \$leafName\ \$body\n\}\n======\n\nAnd\ usage\ something\ like\ this:\n\n======\nforpaths\ \{key\ level\ leaf\}\ \$dirs\ \{...\}\n#\ OR\nforpaths\ \{key\ level\}\ \$dirs\ \{...\}\n#\ OR\nforpaths\ key\ \$dirs\ \{...\}\n======\n\n''Find\ the\ difference\ between\ two\ lists''\n\n======\nproc\ ldiff\ \{a\ b\}\ \{\n\ \ \ \ lmap\ elem\ \$a\ \{\ expr\ \{\$elem\ in\ \$b\ ?\ \[continue\]\ :\ \$elem\}\ \}\n\}\n======\n\n----\n\[AMG\]:\ '''Sorting\ a\ list\ by\ element\ string\ length'''\n\n======\nlsort\ -command\ \{apply\ \{\{a\ b\}\ \{expr\ \{\[string\ length\ \$a\]\ -\ \[string\ length\ \$b\]\}\}\}\}\ \$list\n======\n\n----\n'''\[domino\]\ -\ 2018-05-25\ 16:30:34'''\n\n(First\ time\ edit\;\ forgive\ formatting\ and\ \"where\ on\ the\ page\"\ issues)\n\nRe:\ LPREPEND,\ couldn't\ you\ just\ use\ this?\n\nAll\ produce\ the\ properly-appended\ lists\ (obeying\ listed-ness):\n\ \ \ \ \ \ \ \ -->\ \"\{10\ 11\ 12\ 13\ 14\}\ 25\ \{100\ 101\ 102\ 103\ 104\}\ \{\{10\ 11\ 12\ 13\ 14\}\}\ 0\ 1\ 2\ 3\ 4\"\nNumbers\ given\ (in\ ms):\ (\ 5\ single\ iterations:\ quickest\ ->\ slowest)\ /\ (\ time\ \{code\}\ 1000\ \[iterations\]\ )\nTCL8.6.7\n======\nproc\ lprependDKF\ \{\ var_name\ args\ \}\ \{} CALL {my revision {Additional list functions}} CALL {::oo::Obj3226498 process revision/Additional+list+functions} CALL {::oo::Obj3226496 process}

-errorcode

NONE

-errorinfo

Unknow state transition: LINE -> END
    while executing
"error $msg"
    (class "::Wiki" method "render_wikit" line 6)
    invoked from within
"my render_$default_markup $N $C $mkup_rendering_engine"
    (class "::Wiki" method "render" line 8)
    invoked from within
"my render $name $C"
    (class "::Wiki" method "revision" line 31)
    invoked from within
"my revision $page"
    (class "::Wiki" method "process" line 56)
    invoked from within
"$server process [string trim $uri /]"

-errorline

4