The '''array''' command manipulates [Tcl]'s associative arrays (except for standard reading and writing of array entries, which are treated like normal Tcl [variable]s using the ''array(key)'' syntax.) See http://purl.org/tcl/home/man/tcl8.4/TclCmd/array.htm for the man page description of: '''[array anymore]''' ''arrayName searchId'' '''[array donesearch]''' ''arrayName searchId'' '''[array exists]''' ''arrayName'' '''[array get]''' ''arrayName ?pattern?'' '''[array names]''' ''arrayName ?mode? ?pattern?'' '''[array nextelement]''' ''arrayName searchId'' '''[array set]''' ''arrayName list'' '''[array size]''' ''arrayName'' '''[array startsearch]''' ''arrayName'' '''[array statistics]''' ''arrayName'' '''[array unset]''' ''arrayName ?pattern?'' ---- All ''array'' commands require the ''arrayName'' rather than the array itself - unlike the ''list'' commands (with the only exception of ''[lappend]'' and ''[lset]'' in 8.4). ---- ''Questions that one might have about Tcl arrays'' * How are '''Tcl arrays''' different from what people normally think of '''arrays'''? In '''Tcl''', the array is really better termed a hash map (ala perl) or perhaps a [[use snobol, awk, python, etc. term here ]]. The indexes can be any string, the indexes are not ordered, etc. A '''Tcl''' array isn't restricted to indexes of just numbers. Like wise, it isn't straight forward to get things out of a '''Tcl''' array in the same order as you put them in. Even if you use a number for putting things into the '''Tcl''' array, remember that '''Tcl''' is treating it as any old string. Thus you have t o factor this in when writing code to pull things out of the array. * How are '''Tcl arrays''' different from '''Tcl''' scalar variables? A '''Tcl''' scalar variable contains a string . That string can have some sort of programmer envisioned data s tructure encoded into it - see [list] for one example and [keyed list] for another. * What factors should be considered when determining when to use an array and when to use a list? Arrays use more memory than lists. Arrays provide O(1) access due to their hashtable nature, while lists provide O(1) access only for numerical indices. * What are the naming restrictions, limits, or alternatives for '''Tcl arrays'''? '''Tcl array elements'''? Array names have the same restrictions as any other Tcl variable. Array element names can be any string - however, the value is a literal one. Leading spaces, punctuation, etc. must all match exactly when using retrieving the value. When referencing a specific array element, the element portion is consider e d a part of the name. Thus, if the array name itself requires {} for variable substitution, then the element reference will too. That is to say: array unset {this stuff} set {this stuff(one)} 1 parray {this stuff} * How do you get multiple dim en sion '''arrays''' in '''Tcl'''? There are no multi-dimensional arrays in Tcl but they can be simulated by a naming convention: set a(1,1) 0 ;# set element 1,1 to 0 This works if the keys used do not contain the ',' character. If the keys can be arb itr ary strings then one can use the [list] of the indices as index into the array: set a([list $i1 $i2 $i3]) 0; # set element (i1,i2,i3) of array a to 0 This is completely unambiguous, but might look a bit uglier than the comma solution. Also remember that set a([list 1 2 3]) 0 is equivalent to set {a(1 2 3)} 0 but not to set a(1 2 3) 0 since the last passes four argument to [set]. * How is a [Tk]/[BLT]/'''Tcl''' ''[vector]'' different from an array? * What other array-like variables are implemented in core '''Tcl''' or '''Tcl''' extensions? 1. [TclX] has keyed lists. 1. [NAP] has some sort of array/vector data structure. 1. Tcl's [dictionary] type variable * What is the safe way to code Tcl so that an array element is either incremented or created, depending on whether it exists already or not? proc incrArrayElement {var key {incr 1}} { upvar $var a if {[info exists a($key)]} { incr a($key) $incr } else { set a($key) $incr } } * How do you set an array element? An entire array? set array(element) "Value" array set myArray {} ;# Create an empty array * How do you remove an array element? An entire array? [Bruce Hartweg] recently wrote in news:comp.lang.'''tcl''': unset x ; # x doesn't exist at all anymore unset x ; array set x {} ; # x exists as an array but has no elements array unset x ; # available in recent versions # - same r esults as 2 foreach idx [array names x] { set x($idx) {} } ; # array exists - all the elements still # exist, but values of each element are now # empty * How do you loop through an array, processing everything? See [foreach] , [iterating through an array]. ---- For detailed discussions, see [Arrays / hash maps]; for many usages '''examples''', [A simple database] . See also [parray]. ---- Think ing about using arrays as sets got me wondering: What is the smallest amount of storage that can be taken up by a value in an array? Assuming the keys are what is important to me, I would want to take up the least amount of storage for the values. So, wh at's smallest? An integer (or zero specifically)? An empty string? The key itself? ''--[escargo] 11/11/2002'' '''Lars H''': This is a very tricky question (especially since Tcl does not provide much for [Introspection] into the matter). I had expected that ''any'' value (TclObject) which already exists should yeild the same result, but it seems to matter: Bytes allocated Code --------------- ---------------- 970752 for {set n 1} {$n<10000} {incr n} {set A($n) [expr 0]} 729088 set zero [expr 0]; for {set n 1} {$n<10000} {incr n} {set A($n) $zero} 729088 for {set n 1} {$n<10000} {incr n} {set A($n) 0} 729088 for {set n 1} {$n<10000} {incr n} {set A($n) {}} 1130496 for {set n 1} {$n< 10000} {incr n} {set A($n) $n} 970752 for {set n 1} {$n<10000} {incr n} {set A([format %d $n]) $n} (These measurements were essentially obtained by comparing the vsize (as reported by ps) of tclsh before and after evaluating the above code, hence it is rather crude.) ''[escargo]'': Those last two seem ''strange!'' Why would having the pure string as the name make such a difference in the storage? Makes me wonder what this would be. ??????? for {set n 1} {$n<10000} {incr n} {set A($n) [format %d $n]} Also, isn't there a fence post error here? Shouldn't the range start with ''set n 0''? Otherwise I see 9999 instances being created, not 10,000. ''[Lars H]:'' And 10000 instances would be more natural than 9999 for what reason? We'r e just trying to see what's best, and aren't particularly concerned with how good the best are. As for that mysterious result when the key was used as value, I'm just as surprised as you are. But try it yourself. The code used for obtaining the measureme nts can be found on [Measuring memory usage]. I also set up [Compact data storage] for discussing matters of this kind. ''[escargo] 22 Nov 2002'' - I would think that 10000 would be more natural than 9999 just in terms of thinking about averages. I would rather mentally try to divide a number by 10000 than worry about dividing by 9999. ''[Michael Schlenker]'' - Trying to explain whats going on: Tcl arrays do not yet use Tcl_Obj* for the array keys (some code for it is in the core but #ifdef��´ed out for c ompatib ility reasons) instead they use char* as keys. So 10000 char* are created, with the string reps for 1-10000 for the first 4 examples, but with a larger string rep for the last two examples. Example 1 creates a new Tcl_Obj for every entry, as it ca nnot eas ily be shared. Examples 2,3 and 4 create only one Tcl_Obj that is shared. Examples 5 and 6 create one unshared Tcl_Obj for each entry. ''[Lars H]:'' I might add that the reason that example 5 is more costly than example 6 is that each of the uns hared obj ects in example 5 have a string representation (generated when the argument A($n) of set is substituted), whereas the unshared objects in example 6 do not ([format] makes do with the internal representation). ---- ''[escargo] 19 Nov 2002'' - H ere is ano ther question: What is the most efficient way to determine if the contents of two arrays are the same or different? If '''array get''' had an option to specify the method and order of the results, then a simpler comparison could be done. (In [Icon] a table can be turned into a list by its sort function, which can return the results in one of four ways: 1. List of key, value pairs sorted by key. 1. List of key, value pairs sorted by value. 1. List of alternating key and value sorted by key. 1. List of alternating key and value sorted by value. This puts the table into a known canonical order. There appears to be no way to know that '''array get''' would linearize two arrays in the same way.) It makes me wish there was an '''array compare''' function that could easily answer the question. ''[Michael A. Cleverly] 19 Nov 2002'' - Here's an ''array compare'' type proc: proc array-compare {array1 array2} { upvar 1 $array1 foo $array2 bar if {![array exists foo]} { return -code error "$array1 is not an array" } if {![array exists bar]} { return -code error "$array2 is not an array" } if {[array size foo] != [array size bar]} { return 0 } if {[array size foo] == 0} { return 1 } set keys(foo) [lsort [array names foo]] set keys(bar) [lsort [array names bar]] set keys(keys) $keys(foo) if {![string equal $keys(foo) $keys(bar)]} { return 0 } foreach key $ke ys(keys) { if {![string equal $foo($key) $bar($key)]} { return 0 } } return 1 } ''[Michael Schlenker]'' If using Tcl 8.4 one can speed this up a bit, by optimizing the lsort: proc array-compare2 {array1 array2} { upvar 1 $array1 foo $array2 bar if {![array exists foo]} { return -code error "$array1 is not an array" } if {![array exists bar]} { return -code error "$array2 is not an array" } if {[array size foo] != [array size bar]} { return 0 } if {[array size foo] == 0} { return 1 } ;# some 8.4 optimization using the lsort -unique feature set keys [lsort -unique [concat [array names foo] [array names bar]]] if {[llength $ keys] != [array size foo]} { return 0 } foreach key $keys { if {$foo($key) ne $bar($key)} { return 0 } } return 1 } ''[escargo] 20 Nov 2002'' - So, just to summarize: Arrays a re equal iff ''(if and only if)'' 1. They are equal size. 1. They have the same ''names''. 1. For all the names the values (associated with each name in each array) are equal. Is there a significant performance or space penalty for having to call [lsort] external to '''array names''' instead of having '''array names''' have a parameter that does the sorting internally? The performance and space penalty is insignificant if [lsort] is used as in the above example. ---- array set colors { red #ff0000 green #00ff00 blue #0000ff } foreach name [array names colors] { puts "$name is $colors($name)" } ---- See also [Memory costs with Tcl] for measurement of array/list element consumption in b ytes. ---- * [Arrays as cached functions] * [Arrays of function pointers] * [Persistent arrays] * [Procedures stored in arrays] ---- How would one copy an array? -JR [Lars H]: Usually using array get&set, like so: array set copy [array get original] ---- Passing arrays to procedures * See [How to pass arrays] ''Roelf Diedericks 19 February 2003'' ---- [KJN] Is there a good reason why Tcl does not treat entire arrays as first-class objects? What I mean by this is giving the programmer the ability to refer to the entire array by its "$arrayname" instead of "arrayname", and the ability to use "$arrayname" as the argument of a proc call or as the return value. Of course, because Tcl objects are stored in dual format, the interpreter could implement this without the need to convert back and forth between arrays and strings. Why does Tcl's design tolerate this inconsistent treatment of different types of data? [LV] What string representation would $arrayname have? Referencing a variable as $name needs to always have a string representation. I suppose it might be represented as the same as [[array get arrayName] Is that what you had in mind? [RS] Also, [array]s are collections of variables (so: not a value), and have been in Tcl for a long time. Given modern [dict] and [namespace], they might not even have been invented... [RHS] Would it be unreasonable to treat $arrayName the same as [[array get $arrayName]]? One could shimmer between the array rep and the list (and other) representations by how they are accessed. In that vein, you could do something like: set bob [list a 1 b 2 c 3] puts $bob(a) ...and it would shimmer the list to an array. The only "gotcha" I can think of would be that the list order might? change when you modified the variable as an array, but I don't think that would be unreasonable. ---- I can see namespaces being the preferred method for encapsulation. Still not understanding dict, I don't understand the pros and cons of dicts vs arrays for randomly accessible hash type data structures. ---- See also [Fitting a new Rear-End to Arrays]. ---- [KJN] Yes, [[array get $arrayName]] is a good string representation. What makes me slightly uncomfortable is that Tcl has two types of compound variables (lists and arrays) that are appropriate in different situations and need different handling (with arrays arguably not first-class objects). I wasn't aware of the [dict] (in Tcl 8.5). This would be most useful if it could do everything that lists and arrays can do now, so that lists and arrays can either be deprecated, or implemented in terms of a dict. [RS] protests - [list]s are the most versatile containers (for structs, vectors, matrices, trees, stacks, queues, ...), while [dict]s are more specialized (but can take over most jobs of arrays, except for traces on array elements). I'd like to have both of them in the future :) [LV] Some might say that using lists for vectors and matrices is a bit like using duct tape to hold a boat together... [BLT]'s vector data type is often mentioned as being a useful data structure when vectors are intended for visualization. Also I guess I misremembered dicts as having more restrictions than just traces. [RS] Hm.. vectors are one-dimensional containers for elements - as are [list]s. Matrices are two-(or more-)dimensional containers for elements - as are lists of lists. Tcl lists are implemented in C as Tcl_Obj*[[]], costing ~12 bytes of overhead per list elements. Restricted vectors or matrices could be implemented slightly more efficiently, but would needlessly enlarge the variety of data types that is seen as a problem on this page. Tcl isn't an extreme-performance language (C or Assembler are much better at that), but it has great abstractions (like [list]s and [array]s) to boast. So I'd not call [list]s just "duct tape", but rather: simple yet powerful abstractions of containers. More like Swiss Army Knives :) [AM] I consider Tcl's lists to be very similar to C's arrays and Fortran's one-dimensional arrays, with the added advantages of bound checking, automatic size management and heterogeneous content. That makes them more versatile than either of Tcl's arrays or dicts in many ways, but these have their advantages too ... Compare this to the wealth of data structures that is described in literature! If you only look at the different ways of specialising tree structures! Of course you can do a lot with just C-style arrays. But it does not mean that other structures are not useful from time to time. [DKF]: Tcl arrays have a lot in common with [Java]'s ''java.util.HashMap'' class, as to [dict]s. Tcl [list]s are more like ''ArrayList''s ---- [Category Command] (of [Tcl]) - [Tcl syntax help] - [Arts and Crafts of Tcl-Tk Programming] - [Category Data Structure]