'''[http://www.tcl.tk/man/tcl/TclCmd/list.htm%|%list]''', a [Tcl Commands%|%built-in] [Tcl] [command], creates a [Tcl Rules Redux%|%list]. ** Synopsis ** : '''list''' ?''arg arg ...''? ** Summary ** Returns a list whose elements are the given ''arg'' values (in the same order). Returns an empty list if no arguments are given. ** Documentation ** [http://www.tcl.tk/man/tcl/TclCmd/list.htm%|%man page]: [http://core.tcl.tk/tcl/artifact?filename=generic/tclUtil.c&ci=trunk%|%generic/tclUtil.c]: documentation of the list format [tip%|%Tip] [http://www.tcl.tk/cgi-bin/tct/tip/407%|%407], The String Representation of Tcl Lists: the Gory Details: [tip%|%Tip] [http://www.tcl.tk/cgi-bin/tct/tip/148.html%|%148], Correct [[list]]-Quoting of the '#' Character: ** See Also: ** [Tcl Quoting]: [Is everything a list?]: [Additional list functions]: [Chart of existing list functionality]: [Chart of proposed list functionality]: [Internal organization of the list extension]: [pure list]: A Tcl value for which no string representation has been generated, but for which an internal structured representation has. [Scripted List]: write a list using command and variable substitution, without having to escape the newline between the words, and with the ability to make comments in between words of the list and comment out some words of the list [cmdSplit%|%scriptSplit]: split a command into its logical words, taking possible command substitution into account [string is list]: [Tcl syntax]: ** Standard List Operations ** '''append''': `[lappend]` and `[lset]` '''delete''': `[lreplace]` '''extend''': `[concat]`, `[lappend]`, and `[list]` '''insert''': `[linsert]`, `[lreplace]` '''length''': `[llength]` returns the length of the list, which is always `0` or greater. '''prepend''': `[lreplace]` '''search''': `[lsearch]` '''set''': `[lset]` '''retrieve''': `[lindex]` retrieves an element at a particular position. The position of the first element is `0`. `[lrange]` retrieves a list of elements within the range of two indexes. `[lassign]` assigns of a list to a sequence of variables. '''retrieve''': `[lindex]` retrieves an element at a particular position. The position of the first element is `0`. `[lrange]` retrieves a list of elements within the range of two indexes. `[lassign]` assigns of a list to a sequence of variables. '''transform''': `[join]`, `[lmap]`, `[lrepeat]`, `[lsort]`, `[lreverse]`, and `[split]` '''validate''': To validate the format of a list, use `[lappend]` (with only one argument) or `[string is list]`. `[lappend]` and `[lset]` are the only 2 list commands which use `[lappend]`, `[lassign]`, and `[lset]` are the only 3 list commands which use '''name of a variable containing a list''' rather than the list value itself. ** Description ** `list` creates a new list and appends each ''arg'' to the list. If no ''arg''s `list` creates a new list and appends each ''arg'' to the list, adding [dodekalogue%|%braces] and backslashes to the ''arg'' value such that if the new list is passed to `[eval]`, each argument in the new list becomes a [word] of a [command], and special characters in each word are escaped so that they have their literal interpretations. If no ''arg''s are given, the new list is empty. A '''list''' is an ''ordered [tuple] of values''. In other languages this is sometimes known as an ''array'' or ''vector''. `[list]` and related commands format a list such that it can be interpreted as the words of a command, making Tcl [homoiconic] (see "lists vs commands" below). In contrast with other languages, a Tcl list is not a [data structure], but a [string] that conforms to a specific [data format%|%format] derived from the [dodekalogue%|%rules] of Tcl. The various list commands read and interpret the string value in order to carry out their operations on a list. For performance, they may, and standard Tcl list commands do, cache a structured interpretation for future use, but this is an implementation detail. Together, this list format and the commands that process it comprise an [abstract data types%|%abstract data type]. Because a list is a string, string operations can be applied to it, though the danger exists that string operations will yield an invalid list. See "lists vs danger exists that string operations will yield an invalid list! See "lists vs The items the new list are quoted with [dodekalogue%|%braces] Use `list` to safely form a list without worrying about how to properly quote the words in the list. this is particularly useful when a word in the list contains a character such as `{` or `"` that is easy to misquote: Although a properly-formatted list can be typed out manually, it's usually best to use list look, ma! a \{ list with `" weird characters \} in it ====== ** List Format ** A [script] that contains no [script substitution%|%command substitutions] is a valid list composed of all the words of all the commands in the Every [script] that has no comment lines and doesn't use the `[{*}]` operator is a valid list composed of all the words of all the commands in the script. Conversely, any valid list is suitable for `[eval%|%evaluation]` as a [command]. Not as a [script], but as a command. When [Tcl rules] are stripped of those parts that refer to the operational aspects of command evaluation, they also serve to specify the format of a list. Here are the [dodekalogue%|%Tcl rules] that do not apply to the list evaluation: specify the format of a list. Here are the [dodekalogue%|%Tcl rules] that do not apply to the list evaluation: '''Evaluation''': Command evaluation is not performed. Evaluation of a list consists only of breaking the commands into words. Each [word] encodes an element of the list. The first word, which is the command name in script evaluation, is simply the first value in the list. newline and semicolon: Since no commands are evaluated, command delimiters are not necessary, and these characters lose that special meaning. `#`: Because no routine is looked up or invoked, `#` loses its meaning as a comment indicator. '''[dodekalogue%|%variable substitution]''': Not performed. `$` has no special meaning. '''[script substitution%|%command substitution]''': Since no routines are invoked, command substitution is not performed, and '''`[`''' does not have special meaning. `{*}`: Only useful for script evaluation, so it isn't performed for list evaluation `{*}`: Only useful for script evaluation, so it isn't permitted for list evaluation In all other respects, list evaluation is identical to script evaluation. '''[Dodekalogue%|%double quotes]''', '''[Dodekalogue%|%braces]''', and '''[Dodekalogue%|%backslash substitution]''' are all processed as usual. Beware of [double substitution]. Tcl does its standard processing on the arguments to `[list]`, and then `[list]` processes them again. The [empty string] is a list that contains no words. Enclosing a well-formed list in braces results in a list containing exactly one [word], which is the original list, but enclosing an arbitrary string of [word], which is the original list, but enclosing an arbitrary value in braces succesfully working with lists in Tcl is to understand that although braces (`{` and `}`) are often used to delimit individual words in lists, braces do not mean "list". They are simply an escaping mechanism for some of Tcl's special characters, e.g., whitespace. As [DGP] put it, "Don't imagine that braces have magic list-ifying powers." Double quotes and braces are essentially syntactic sugar for backslash escaping. [PYK] 2015-04-16: For example, although braces are a very convenient way to represent nested lists, it's usually possible to represent the same nested ====== puts [lindex {a {b c {d e f g}}} 1 2] ;# -> d e f g puts [lindex a\ b\\\ c\\\ d\\\\\\\ e\\\\\\\ f\\\\\\\ g 1 2] ;# -> d e f g ====== Not that one would want to write code like with all those backslashes. It just illustrates the point that when interpreting a string as a list, braces merely escape the normal interpretation of whitespace as the delimiter between elements in the list. They are only indirectly involved in the interpretation of a value as a nested listed by virtue of their effect on whitespace. Braces by themselves do not mean "list". [AMG]: "Usually" possible? I'm sure you mean "always" possible. Backslash quoting can be used to encode any value whatsoever, even those that don't play nice with the brace quoting rules, e.g. a string containing characters immediately after the close brace. [PYK] 2015-04-16: Check. Make that "always possible". Double quotes and braces are essentially syntactic sugar for backslash escaping. ** A Note on Terminology ** This page discusses both the syntax of a list as a string as well as operations In lower-level languages, a list is implemented as some [data structure], and in general, the units that compose a data structure are called '''elements'''. This term applies to data structures in general. There is a subtle but distinct difference between an element of a data structure and an item in a list. In a data structure, an element may be employed to represent an '''item''' in the list, but it may also contain additional information, such as a reference to the element containing containing the next item in the list, for example. Because there is often a one-to-one relationship between an element in a data structure and an item in the list the data structure implements, "element" is often used in place of "item", and this is true both of the content of this wiki and the Tcl documentation. "Item" is the more apt term. of a list as an [abstract data type]. In the [dodekalogue%|%rules] of Tcl, "word" list as an [abstract data type]. In the [dodekalogue%|%rules] of Tcl, "word" format of a list. On this page, "word" is used in this technical sense to refer specifically to a component of a string that represents a list. In other places it's used in the common non-technical sense. Enough context should be provided to differentiate the two meanings. ** Lists vs Commands ** Because both [Dodekalogue%|%commands] and lists use whitespace to delimit words, every valid list is a valid script. However, not every words, every valid list is a valid command. However, not every valid command is a valid list: ====== % llength {set b [list $one "$two $three"]} list element in quotes followed by "]" instead of space ====== The `]` at the end of the command is a violation of the '''[Dodekalogue%|%double quotes]''' rule, which states that `"` terminates a quoted word. A space could be added to turn it into a well-formed list: ====== % llength {set b [list $one "$two $three" ]} 6 ====== Notice that although it is logically a three-word command, because of [Dodekalogue%|%command substitution] the last word in the command is actually composed of four words from the list. ** Lists vs Strings ** ** Strings that Are Lists ** (this section represents [pooryorick]'s crazy-but-not-entirely-without-insight interpretation. While some disagree vehemently with assertions below, they contain some useful ways to think about lists) In contrast with other languages, a Tcl list is not a [data structure], but a [string] representing a data structure, i.e., a [data format%|%textual data format]. The various list commands derive a list data structure from this string value in order to carry out their operations. For performance, they build and internally cache a [C] data structure containg a C array containing one [Tcl_Obj] for each list element, but this is an implementation detail, not specified in the [dodekalogue%|%rules] of Tcl. A conformant implementation of Tcl is free to use any strategies or data structures it likes to operate on lists, as long as the semantics of the commands are preserved. An empty string is an empty list: ====== % set list [list] % llength $list 0 % set list {} % llength $list 0 % set list "" % llength $list 0 ====== A string containing nothing but whitespace is also an empty list: ====== % set list { } % llength $list 0 % set list \n % llength $list 0 set list \t\n\t llength $list ;# -> 0 ====== A string that contains no whitespace is often, but not always a list (containing one word): ====== % set list hello % llength $list 1 % set list he\{llo % llength $list 1 % set notalist \{hello % llength $notalist unmatched open brace in list ====== The following is a list that contains one word, which is an empty string: ====== % set list {{}} % llength $list 1 % set list [list {}] llength $list ;# -> 1 ====== Whitespace separates words in a list: ====== % set list {1 2} % llength $list 2 % set list "1 2" % llength $list 2 ====== Here is a list that contains two words, both of which are empty strings: ====== % set list {{} {}} % llength $list 2 ====== List commands parse strings into lists in much the same way that Tcl parses strings into commands. In the following example, `[llength]` parses the string into a list, and the backlash-space sequence results in the first character of the second word being a space character: ====== % set list {1 \ 2} % llength $list 2 ====== It is very common, and perfectly acceptable, to use braces instead of `list` when writing a list: ====== % set list {one two three} % llength $list 3 ====== But in Tcl, braces are simply a means of escaping whitespace and other special characters in strings. They are a nice way to write out lists, but Tcl itself doesn't equate braces with lists. Any quoting can be used to make a well-formed list, and there are an infinite number of ways to produce a string that is the same well-formed list: ====== % set list "one two three" % llength $list 3 % set list one\ two\ three % llength $list 3 % set list one\x20two\x20three % llength $list 3 % set list one\ttwo\tthree\t % llength $list 3 #... and on and on ... ====== When formatting a list as a string, `list` will escape values where necessary: ====== % list \n\{ \n\{ ====== ** Strings that Are Not Lists ** [EIAS%|%All lists are strings], but not all strings are well-formed lists. The various list commands expect their arguments to be well-formed lists. To check whether a string is a list: ====== string is list $somevariable ====== Alternatively: ====== catch {llength $somevariable} ====== When doing experiments to understand lists, it is a good idea to first assign the values in question to variables before operating on them, since it is hard to keep track of when quoting is interpreted as Tcl parses the command, and when the command is interpreting the values it has received as arguments. This makes it possible to first inspect the value of the string before passing it to a command: ====== % set var1 \{ { ====== Many simple strings are lists: ====== % llength hello 1 % llength hello\ world 2 % llength {how I made a great mistake in quotation} 8 ====== Some strings, however, are '''not''' lists: ====== % llength \" unmatched open quote in list % llength \{ unmatched open brace in list % llength "ab{ {x y" unmatched open brace in list % llength \{}a list element in braces followed by "a" instead of space % llength {{a b} {c}]} list element in braces followed by "]" instead of space % llength {{*}exactitude} list element in braces followed by "exactitude" instead of space ====== ** Canonical Representation ** A single list may be represented by different combinations of double quotes, braces, and A single list may be represented by different of double quotes, braces, and but the latter is the canonical representation of the list. To produce the canonical representation of a list: ====== list {*}$somelist ====== One quick and dirty way to check for list equality is to compare their canonical representations as a string: ====== expr {[list {*}$list1] eq [list {*}$list2]} ====== This may be undesirable if the lists are large, because the string values of both `$list1` and `$list2` are generated if they haven't been already. Another thing `list {*}$list1` does is armor special characters against possible interpretation if evaluated as a Tcl script: ====== % list {*}{puts $hello; set b [list $one $two $three]} puts {$hello;} set b {[list} {$one} {$two} {$three]} ====== In other words, a list is formed such that the following is true ([http://wiki.tcl.tk/440#pagetocad1fdaa5%|%1]): ====== expr {[eval list $list] eq [list {*}$list]} ====== ** Using Braces to Write Lists ** In source code, braces are often used to write lists. One example is the arguments to `[proc]`: ====== proc move {element speed args} ... ====== It would be a bit awkward, and a bit slower, to use `list` for that: ====== proc move [list element speed args] ... ====== Likewise, literal braced strings are used with `[switch]` (in the braced patterns-and-bodies form), and `[string map]` (the map is a list). These braced strings are usually not a problem, but you may need to think about list formatting when special characters (backslash, braces, whitespace, quotes) are involved. Sometimes, an extra layer of braces are required around a word in a list, but if it is unbalanced with respect to braces then you may need to backslash-escape all special characters in it instead. Braces are also used to escape the body of a `[proc]`, but in that case, the body is not parsed as a list, but as a script (unescaped newlines take on special meaning): ====== proc myproc {} { this is not parsed as a list, but as a script } ====== ** Generating Code ** Tcl is a dynamic language which allows for the construction of Tcl scripts at runtime. Since each command is a list, and a script is a sequence of lists, list operations are often used to build up commands and scripts that can then be interpreted using `[eval]`, `[apply]` and friends. When substituting some piece of information into the dynamically-generated script, it is usually necessary to subtitute in a list, even if the context requires a single value. [string map] is can be used for this purpose. ---- [KBK] writes on comp.lang.tcl (with some modifications): If a string has been built up using the list commands, for instance `[list]` and `[lappend]`, then it is always well-formed as a command. The first word of the list (word number zero) will be the command name and the remaining words will be what the command sees as its parameters. This method, in fact, is one of only a very few ways to construct command strings that have the desired parameters when one or more of the parameters contains user-supplied data, possibly including nasties like backslashes or unbalanced braces. In particular, using double-quotes and the string commands such as `[append]` and `[subst]` is NOT safe for constructing command strings with arbitrary data. Moreover, `[eval]` and its friends give you special support for the technique of using lists as commands. If a command being evaluated is a "pure" list, that is, one that was constructed using the list commands and has never acquired a string representation, then the evaluator is able to short-circuit the parsing process, knowing that all arguments have been substituted. It doesn't need to do the (fairly expensive) scan for $- []- and \- substitution, nor balance "" and {}, but can go directly to looking up the command name and invoking it. ** Using List to Concatenate Lists ** `list` can be used with [{*}] to the same effect as `[concat]`: ====== set a {a b c}; set b {d e f} list $a $b ;# -> {a b c} {d e f} concat $a $b ;# -> a b c d e f list {*}$a {*}$b ;# -> a b c d e f ====== See [Concatenating lists] for a timing comparison of the various methods. ** Concatenating Lists ** The following three methods for concatenating list are roughly equivalent in performance: ====== set list hello concat $list $list list {*}$list {*}$list lappend list {*}$list ====== The difference is that `[concat]` does not make sure its arguments are valid lists, and `[lappend]` modifies `$list` Before the advent of the [{*}] operator, the following syntax was used: ====== eval [list lappend baseList] $extraList ====== ** Newline-delimited Lists ** When writing a list of lists to a file, it's useful to represent it using the newline character to separate the words of the lists. Here's how to do that: ====== foreach list $tosave { puts $chan \{ foreach word $list { puts $chan [list $word] } puts $chan \} puts $chan {} } ====== The result is a list of lists, having the same length as `$tosave`. ** Internal Structured Representation ** Internally, Tcl tracks the structure of the list, and the various list commands take advantage of this to improve performance to O(1) time (access time does not depend on the total list length or position within the list). A string representation of a list is not made until is is needed. Therefore, a `[string]` operation on a large list may incur a dramatic performance/storage penalty if it causes the string representation has to be generated. The rule of of thumb is to use list-aware commands for lists, and avoid string commands. One obvious exception to this rule is `[string is list]`, which is smart enough not to generate the string representation of a pure list. `[concat]` is a string operation, but is smart enough not to incur the penalty if all its arguments are pure lists. The internal representation of a list should be transparent at the script level, but for the curious: In the [C] implementation of Tcl 8.x, a list is a type of [Tcl_Obj], The elements of a list are stored as C-style vectors of pointers to the individual [Tcl_Obj] element values, plus some extra data. The consequence of this is that `[llength]` and `[lindex]` are constant-time operations — they are as fast for large lists as they are for small lists. ** `[concat]` ** `[concat]` also operates on lists, but does not require that its arguments be valid lists. `[foreach]` operates on lists. `[split]` creates lists, and `[join]` consumes them. Various other commands also make use of lists. Since all values, including lists, [EIAS%|%are strings] (but not all strings are lists!), it is possible to use `[string]` commands on lists, but performance can suffer and there are usually better ways to accomplish the task. In some common cases, Tcl is smart enough to do the right thing. For example, doing a string comparision between a list and the empty string is perfectly acceptable, and just as performant as the `[llength]` variant: ====== proc foo {bar args} { if {$args eq {}} then { #string comparison might force internal Tcl gyrations set args $::foo::default_for_args } # ... } ====== The `[llength]` variant: ====== proc foo {bar args} { if {[llength $args] == 0} then { # $args is empty set args $::foo::default_for_args } # ... } ====== ** Layers of Interpretation ** In the following example, the value of `a_single_backslash` is a single backslash: ====== set a_single_backslash [lindex \\\\ 0] ====== prior to evaluating the lindex command, Tcl performs backslash substitution on the four backslashes, so that the first argument becomes two backslashes. To convert the first argument to a list, the `[lindex]` command then performs backslash on substitution on the two backslashes, resulting in one backslash, which is then assigned to `a_single_backslash`. ** Converting a String to a List ** `[split]` takes a string and returns a list, but the best choice depends on the task at hand. `[regexp]` is often handy: ====== set wordList [regexp -all -inline {\S+} $myGnarlyString] ====== [DKF] proposed this pretty alias: ====== interp alias {} listify {} regexp -all -inline {\S+} ====== [Bill Paulson] notes that this alias changes all white space to a single space, which might or might not be what you want. Other than that, this '''listify''' is effectively a `[split]` that interprets adjacent delimiters as as a single delimiter rather than interpreting them as delimiting an empty string, like `[split]` does. (2014-09-08): this can also be used to duplicate words in a list: [PL] (2014-09-08): this can also be used to duplicate words in a list: ====== regexp -all -inline {\S+} {a b c} # => a b c regexp -all -inline {(\S+)} {a b c} # => a a b b c c regexp -all -inline {((\S+))} {a b c} # => a a a b b b c c c ====== etc. ** Validating a List ** Various ways to check whether a string is a list: ====== string is list $some_value catch {lindex $some_value 0} catch {llength $some_value} ====== In later versions of Tcl, [string is list] is available. ** List Vs. List of Lists ** [escargo] 2003-03-16: How can you tell if a value is a string of words '''or''' a list of strings of words? The practical application that I had for this was an error-printing proc. It could be passed a value that might be a single error message or a list of error messages. If it were a single error message, then I could print it on one line; if it were multiple messages, then I wanted to print each on its own line. So, how could I distinguish between the cases? I think I eventually made all sources of errors provide a list of errors, even if was always a list of 1 (instead of just the error message string). But the question always stuck with me? Was there a way I could have easily distinguished between the two? Could I look at the representation and see an opening curly brace if it were a list? [RS]: The (outer) curlies are not part of the list - they are added, or parsed away, when needed. Tcl [list]s are not fundamentally different from strings, rather, I'd say they are a "view" on strings. Just as `42` can be viewed as string, or integer, it can also be viewed as a one-word list. Except if you introduce your own tagging convention, there is no way of telling whether a list is in reality a string - in the other direction, only strings that cannot be parsed as lists (unbalanced braces, quotes..) cannot be viewed as lists. But for your concrete error-printing problem: if you simplify the interface to "a list of one or more error messages", you can have the desired effect with ====== puts [join $errormessages \n] ====== Just make sure that the "one message" case is properly nested, e.g. ====== errorprint {{This is a one-liner}} errorprint "{This too, with a $variable reference}" ;# braces in quoted strings allow substitution errorprint [list "another $variable reference"] errorprint {{Two messages:} {This is the second}} ====== ** Single-word Lists vs non-list value ** Many simple string values can also be interpreted as single-word lists. Programs should use additional data or rely on program logic to decide whether a value should be interpreted as a list or a string. Here is another way of looking at the problem (`[lindex]` without an index returns the list argument unchanged): ====== % lindex a a % lindex a 0 a % lindex [lindex a 0] 0 a % lindex [lindex [lindex a 0] 0] 0 a % lindex {a} a % lindex {a} 0 a % lindex [lindex {a} 0] 0 a % lindex [lindex [lindex {a} 0] 0] 0 a % lindex {{a}} {a} % lindex {{a}} 0 a % lindex [lindex {{a}} 0] 0 a % lindex [lindex [lindex {{a}} 0] 0] 0 a % lindex {{{a}}} {{a}} % lindex {{{a}}} 0 {a} % lindex [lindex {{{a}}} 0] 0 a % lindex [lindex [lindex {{{a}}} 0] 0] 0 a ====== No program can tell the difference between the string "a" and the one-word list "a", because the one-word list "a" ''is'' the string "a". [Dossy] 2004-02-26: A co-worker yesterday who is new to Tcl discovered something that surprised me -- [nested list]s in Tcl don't work as I expected in a very specific case: ====== % list [list [list x]] x ====== Um, when I ask for a list of a list of a list with the single word 'x', I would expect '{{{x}}}' back. However, you just get 'x' back. Thinking about it, I understand why, but it means that Tcl lists alone cannot be used to represent ALL kinds of data structures, as Tcl lists magically collapse when it's a series of nested lists with the terminal list having only a single bare word that requires no escaping. [Lars H]: It looks worse than it is. For one thing, it is only the string representation that collapses, not the internal representation, so the above nesting of `list` is not completely pointless. It is furthermore very uncommon (and this is ''not'' specific to Tcl) that nesting depth alone has a significance. Either you know the structure of the value, and thereby the intended nesting depth, or the list is some generic "thing", and in that case you anyway need a label specifying what kind of thing it is. [DBaylor]: I think this is actually worse than it looks. I see lots of people trying to learn Tcl and the #1 point of confusion is Dossy's example. But what I really dislike about this behavior is that it hides bugs until specific input is encountered. If you ever mix up your data-types (string vs. list), your code will work fine 99% of the time - until special characters are involved. These bugs are inevitably found the hard way. Oh how I wish `[list] x` returned `{x}`. [PYK] 2013-10-27: What would `[lindex] x 0` return, then? An error that `x` is not a list? All commands are lists (after adjusting for [Dodekalogue%|%command substitution]), and `x` is potentially a valid command. Therefore, `x` must be a list. There is some subtlety to Tcl which can take a little time for beginners to wrap their heads around, but this subtlety is Tcl's strength, not its weakness. The gripe about hiding bugs until specific inputs are encountered is a gripe about dynamic languages in general, and not particular at all to Tcl. ** Subsetting a List ** [LV] Question: in [Perl], [Python], and a number of other languages, one has the ability to read and write to subsets of a list -- ''slices'' -- using an almost array like notation. Is this something that one could simulate without much grief in Tcl? [RS]: But of course - our old friends (with wordier notation) ====== set slice [lrange $list $from $to] set newlist [eval lreplace [list $otherlist] $from $to $slice] ====== `[lset]` can only replace a single element, but possibly several layers deep in the nesting. For reading access to a slice of a list, check [Salt and sugar] for how the following is implemented: ====== set i [$ {a b c d e f g} 2 4] ==> {c d e} ====== ** Flattening a List ** To flatten a list: ====== concat {*}$nested ====== It can be applied multiple times: ====== proc flatten data { concat {*}$data } set a {{a {b c}} {d {e f}}} ; # {a {b c}} {d {e f}} flatten $a ; # a {b c} d {e f} flatten [flatten $a] ; # a b c d e f ====== alternatively: ====== set flattened [join $mylist] ====== Another possibility: ====== foreach e $list { foreach ee $e { lappend flatList $ee } } ====== `[eval]` is not a good option because it chokes on newlines: ====== % eval concat {a b} ambiguous command name "b": binary break ====== The newline in the argument ends `[concat]` and starts a new command. This is due neither to `[concat]` nor to the [tclsh] prompt loop, but to the nature of `[eval]`. To get around that issue, first pass the value through a command that parses strings into valid lists: ====== eval concat [lrange {a b } 0 end] ====== [RS] 2004-02-26: If you really want to flatten a list of any depth, i.e. remove all grouping, I think this way is simplest (and robust): ====== proc flatten list { string map {\{ "" \} ""} $list } % flatten {a {b {c d {e f {g h}}}}} a b c d e f g h ====== [Lars H]: No, that won't work. Consider ====== % flatten [list \{ \}] \ \ ====== I'd give you that it isn't exactly clear what should happen to lists with such words, but the above doesn't get a single character right. [RS] admits he was thinking of well-behaved lists (as built with `[list]` and `[lappend]`, where braces are only generated mark-up, not content :^) You're right to point out that ''flatten'' is not chimpanzee-proof, and robust, enough. [cyrilroux] 2010-10-28: Maybe here is the solution to solve the escape issue? This always consist in replacing all { and } but NOT \{ and \} (escaped ones). That is to say 6 cases: "^{" " {" "{{+" "}$" "} " "}}+" ====== proc lflatten list { regsub -all {^\{| \{|\{\{+|\}$|\} |\}\}+} $list { } flatten return $flatten } % set foo {{a {b c}} {d\{d\{ {e f} g}} % lflatten $foo a b c d{d{ e f g ====== [CMP]: In general, string manipulation on lists all have the same problem; they do not consider the list structure (unless copying the complete implementation of the existing list commands). Hence, all list manipulations should be done using existing list commands. ** Information about struct::list - extended list operations ** [Tcllib] now contains a [struct::list] module. Its documentation can be found at http://tcllib.sourceforge.net/doc/struct_list.html. [dgp] offers this example of making use of it: ====== % package require struct 1.3 1.3 % namespace eval my { namespace import ::struct::list set l [::list 1 2 3] puts [list reverse $l] } 3 2 1 ====== More explanation… In the above example, is the use of ''::list'' in the set command vs ''list'' in the [puts] command merely an example of different ways of referring to portions, or does one refer to the original tcl list versus the imported new list command? [MG] I believe ''::list'' in the above refers to the Tcl list command, and ''list'' refers to the imported ''::struct::list'' (which is then also ''::my::list'', as it's imported). Or at least I think that's right. Namespaces used like that require a lot more sleep than I've had lately ;) ** What would a Tcl version of the list command look like? ** [AMG]: Is this an acceptable implementation of `list`? ====== proc list args { return $args } ====== Looks right to me... [RS]: To me too. That's because ''args'' is already a list, as by the Tcl parser... I'd just write ====== proc list args {set args} ====== [AMG]: Chuckle. ====== proc list args [list set args] ====== ** Transform a list into a list of fixed size lists ** [LV]: in response to a question, Jonathan Bromley, 2008-05-30, [comp.lang.tcl], wrote the following Tcl proc for turning a long list into a list of lists: ====== proc split_list {L {n 50}} { incr n 0; # thanks to RS for this cool "is it an int" check! set result {} set limit [expr {[llength $L] - $n}] for {set p 0} {$p <= $limit} {incr p $n} { lappend result [lrange $L $p [expr {$p+$n-1}]] } return $result } ====== [arg]: Just the code I wanted (needed to split results from SQLite). Thanks. But can I suggest a few tweaks:- 1. name changed to "partitionlist", I think it's less ambiguous than "split_list". Any ideas for a better name? 2. change default from 50 to 2, splitting into pairs looks a more useful default. 3. change setting/comparing "limit" so that all the elements of the original list are copied, the original version acted as if the original list were truncated to a multiple of the requested sublist length. This version will output any "extra" elements as another short sublist. ====== proc partitionlist {L {n 2}} { incr n 0; # thanks to RS for this cool "is it an int" check! set result {} set limit [llength $L] for {set p 0} {$p < $limit} {incr p $n} { lappend result [lrange $L $p [expr {$p+$n-1}]] } return $result } ====== [Lars H]: If the partitioned list is then immediately going to be iterated over, it may of course be easier to take advantage of the fact that the variable arguments of [foreach] are really lists of variables. I.e., instead of ====== foreach row [partitionlist $data 3] { lassign $row first second third # Further processing... } ====== one can just do ====== foreach {first second third} $data { # Further processing... } ====== Conversely, this can be used for the following [braintwisters]' implementation of '''partitionlist''': ====== proc partitionlist {L {n 2}} { set varlist {} set body {lappend res [list} for {} {$n>0} {incr n -1} { lappend varlist $n append body { $} $n } set res {} foreach $varlist $L [append body \]] return $res } ====== ** Other uses of `[list]` ** [AMG]: When given no arguments, `[list]` returns empty string. I find this useful when entering Tcl commands interactively, e.g. into [tkcon] or [tclsh]. When I know that a command will produce a lot of output, such as `[read]`'ing a whole file, and I don't want to have it all on my screen, I tack "; list" onto the end of my command line. ====== $ tclsh % set chan [open bigfile] file12dcd00 % set data [read $chan]; list % close $chan ====== If not for the `; list`, the second line would flood my terminal with lots and lots of garbage. [AMG]: Another use for list is to pass it a single argument which it will then return. For an example, see SCT & [RS]'s comments on the page for `[if]`. However, this works due to the "problem" noted above by [Dossy] 2004-02-26. Often the argument requires quoting to become a single-word list, in which case list will ''not'' return its argument verbatim. On the `[return]` page I discuss a few other, safer approaches. The simplest one is to instead use single-argument `[lindex]`. ** Some Tcl core commands require lists as argument or return lists ** `[after]`: `[apply]`: `[array]`: `[binary]`: `[chan]`: `[dde]`: `[dict]`: `[oo::define]`: `[oo::next]`: `[encoding]`: `[exec]`: `[fconfigure]`: `[file]`: `[glob]`: `[http]`: `[info]`: `[interp]`: `[library]`: `[msgcat]`: `[namespace]`: `[open]`: `[package]`: `[packagens]`: `[pid]`: `[pkgMkIndex]`: `[platform]`: `[proc]`: `[read]`: `[oo::refchan]`: `[regexp]`: `[registry]`: `[return]`: `[safe]`: `[scan]`: `[oo::self]`: `[socket]`: `[switch]`: `[tcltest]`: `[tm]`: `[trace]`: ** Page Authors ** [DKF]: [PYK]: ** References ** 1: [aspect], [Tcl Chatroom], 2014-09-13