In addition to the built in
list commands, Tcl (since release 8.4) has been shipped with an additional
struct::list package which includes additional procs (commands) you can use for manipulating lists.
::struct::list longestCommonSubsequence sequence1 sequence2 ?maxOccurs?
::struct::list longestCommonSubsequence2 sequence1 sequence2 ?maxOccurs?
::struct::list lcsInvert lcsData len1 len2
::struct::list lcsInvert2 lcs1 lcs2 len1 len2
::struct::list lcsInvertMerge lcsData len1 len2
::struct::list lcsInvertMerge2 lcs1 lcs2 len1 len2
::struct::list reverse sequence
::struct::list shuffle list
::struct::list assign sequence varname ?varname?...
::struct::list flatten ?-full? ?--? sequence
::struct::list map sequence cmdprefix
::struct::list mapfor var sequence script
::struct::list filter sequence cmdprefix
::struct::list filterfor var sequence expr
::struct::list split sequence cmdprefix ?passVar failVar?
::struct::list fold sequence initialvalue cmdprefix
::struct::list shift listvar
::struct::list iota n
::struct::list equal a b
::struct::list repeat size element1 ?element2 element3...?
::struct::list repeatn value size...
::struct::list dbJoin ?-inner|-left|-right|-full? ?-keys varname? {keycol table}...
::struct::list dbJoinKeyed ?-inner|-left|-right|-full? ?-keys varname? table...
::struct::list swap listvar i j
::struct::list firstperm list
::struct::list nextperm perm
::struct::list permutations list
::struct::list foreachperm var list body
Those commands which are show in bold above are shown in the following example. Firstly, load the package:
package require struct::list
Set up a list, and reverse the order of the elements:
set outbound {Swindon Chippenham Melksham Trowbridge Westbury}
set inbound [struct::list reverse $outbound]
puts $outbound
puts $inbound
give you
Swindon Chippenham Melksham Trowbridge Westbury
Westbury Trowbridge Melksham Chippenham Swindon
Modify each member by running your own coommand (proc) on it:
proc aok where {
append where " on time"
return $where
}
set running [struct::list map $outbound aok]
puts $running
And here is the resulting list:
{Swindon on time} {Chippenham on time} {Melksham on time} {Trowbridge on time} {Westbury on time}
Alternatively, you can pass each member of a list into a new type of loop - the
mapfor loop. I could have also written this using
foreach, mind you!
struct::list mapfor place $inbound {
puts -nonewline "[string toupper $place ], "
}
And that outputs:
WESTBURY, TROWBRIDGE, MELKSHAM, CHIPPENHAM, SWINDON,
The
filter subcommand lets you select list members based on a criteria. There is also a
filterfor
proc pork raw {string match *ham $raw}
set ham [struct::list filter $outbound pork]
puts $ham
And that gives just
Chippenham Melksham
I can use
repeat to clone copies of one or more items into a list, and if those items themselves are lists I will end up with a list of lists:
set rota [struct::list repeat 5 $outbound $inbound]
puts $rota
which looks like this:
{Swindon Chippenham Melksham Trowbridge Westbury} {Westbury Trowbridge
Melksham Chippenham Swindon} {Swindon Chippenham Melksham Trowbridge Westbury}
{Westbury Trowbridge Melksham Chippenham Swindon} {Swindon Chippenham
Melksham Trowbridge Westbury} {Westbury Trowbridge Melksham Chippenham Swindon}
{Swindon Chippenham Melksham Trowbridge Westbury} {Westbury Trowbridge
Melksham Chippenham Swindon} {Swindon Chippenham Melksham Trowbridge Westbury}
{Westbury Trowbridge Melksham Chippenham Swindon}
If I want it as a single list, I can then use
flatten
set asone [struct::list flatten $rota]
puts $asone
and end up with results like this:
Swindon Chippenham Melksham Trowbridge Westbury Westbury Trowbridge Melksham
Chippenham Swindon Swindon Chippenham Melksham Trowbridge Westbury Westbury
Trowbridge Melksham Chippenham Swindon Swindon Chippenham Melksham Trowbridge
Westbury Westbury Trowbridge Melksham Chippenham Swindon Swindon Chippenham
Melksham Trowbridge Westbury Westbury Trowbridge Melksham Chippenham Swindon
Swindon Chippenham Melksham Trowbridge Westbury Westbury Trowbridge Melksham
Chippenham Swindon
As an alternative, I could use the
{*} (expand) notation to expand my incoming lists before I repeat them, thus saving the double step of producing a list of lists which then had to be flattened:
set rota [struct::list repeat 5 {*}$outbound {*}$inbound]
puts $rota
Which directly gives me:
Swindon Chippenham Melksham Trowbridge Westbury Westbury Trowbridge Melksham
Chippenham Swindon Swindon Chippenham Melksham Trowbridge Westbury Westbury
Trowbridge Melksham Chippenham Swindon Swindon Chippenham Melksham Trowbridge
Westbury Westbury Trowbridge Melksham Chippenham Swindon Swindon Chippenham
Melksham Trowbridge Westbury Westbury Trowbridge Melksham Chippenham Swindon
Swindon Chippenham Melksham Trowbridge Westbury Westbury Trowbridge Melksham
Chippenham Swindon
Finally, here are
shift to take the first element off a list, and
swap to swap over two elements:
set starts [struct::list shift outbound]
puts "Runs from $starts to $outbound"
struct::list swap outbound 0 3
struct::list swap outbound 1 2
puts "Runs back from $outbound to $starts"
And that produces:
Runs from Swindon to Chippenham Melksham Trowbridge Westbury
Runs back from Westbury Trowbridge Melksham Chippenham to Swindon
struct::list also supports database-like joining, tools for producing all permultations of a list, a randomiser to shuffle a list, and a series of lcs or longestCommonSequence commands which are designed for data comparison where you're looking for differences.
Full source of the above is
[here]. We'll introduce you to lists, and struct::list too, on our
Tcl, Tk and Expect courses.
(written 2012-02-18)
Associated topics are indexed as below, or enter http://melksh.am/nnnn for individual articles
T206 - Tcl/Tk - Lists [144] Tcl sandwich - lists in Tcl - (2004-12-08)
[463] Splitting the difference - (2005-10-13)
[781] Tcl - lappend v concat - (2006-06-27)
[1282] Stringing together Tcl scripts - (2007-07-29)
[1283] Generating traffic for network testing - (2007-07-29)
[1334] Stable sorting - Tcl, Perl and others - (2007-09-06)
[1402] Tcl - append v lappend v concat - (2007-10-23)
[1405] Sorting in Tcl - lists and arrays - (2007-10-24)
[1601] Replacing the last comma with an and - (2008-04-04)
[2468] What are Tcl lists? - (2009-10-22)
[2472] split and join in tcl and expect - (2009-10-23)
[3285] Extracting data from a string / line from file - Tcl - (2011-05-10)
[3394] The difference between lists and strings - Tcl - (2011-08-16)
[3415] User defined sorting and other uses of callbacks in Tcl and Tk - (2011-09-02)
[3582] Tcl collections - lists, dicts and array - (2012-01-16)
[3583] Expanding a list of parameters in Tcl - {*} and eval - (2012-01-17)
[4209] Lists in Tcl - fundamentals in a commented source code example - (2013-11-16)
[4454] Everything is a string - even a list - (2015-03-11)
[4455] Working out distance between places, using OS grid references and a program in Tcl - (2015-03-11)
Some other Articles
Loading Ruby classes - where does Ruby look?Matching regular expressions, and substitutions, in RubyFinding the total, average, minimum and maximum in a programRuby v Perl - a comparison examplelists and struct::list in Tcl - Introduction to struct::list and examplesThe fileutil package and a list of file system commands in TclBus top - colours of LondonHistoric documents for WiltshireTcl - dicts - a tutorial and examplesKeeping Business Local. But is that realistic?