Updated 2016-06-24 23:25:22 by Casteele

parray - print an array's keys and values

http://purl.org/tcl/home/man/tcl8.5/TclCmd/library.htm
parray arrayName

Print on standard output the names and values of all the elements in the array arrayName. ArrayName must be an array accessible to the caller of parray. It may be either local or global.

In fact, it's more like this:
parray arrayName ?pattern?

Print on standard output the names and values of all the elements in the array arrayName that match pattern. If pattern is not specified, then all of the elements of the array are included in the result. If pattern is specified, then only those elements whose names match pattern (using the matching rules of string match) are included. ArrayName must be an array accessible to the caller of parray. It may be either local or global.

parray prints an array's keys and values, in key alphabetic order and formatted to the longest key name, to stdout. RS

Sometimes, a developer erroneously tries to do something like this:
 set str [parray env]

or some other array. parray only produces output to stdout. Just copy /installdir/tcl/lib/tcl8.4/parray.tcl and modify to accumulate a string rather than calling puts . Call the proc something else, though, or you may unintentionally impact some other tool.

LES on 10-18-2008: I just don't get it. A command/proc that returns data can be used in two ways: returning the data or printing it to stdout - because printing the output of a command that returns data is trivial. But a command/proc that will adamantly output to stdout only is half as useful (or even less than half). It can't simply return the data or feed it to a variable as in the set str [parray env] example above. What is the point of limiting parray like that? Imagine if all commands had that limitation, how much harder life would be.

DKF: The parray command prints an array, just as puts prints a string. The equivalent for scripted processing is array get.

[Maria] - 2010-06-11 08:33:15

yes, DFK, but puts, unlike parray, can take a channelId argument to instruct it to print to a specific channel.

[LIV] - 2010-02-01 17:19:35

puts $var can be redirected to a file, but parray can't. The format from [array get ARRAYNAME] does not look good when write them to a file.

LV: LIV makes a good argument. I recommend you submit a feature request at http://tcl.sf.net/ requesting that parray support an optional channel.

Lars H: You may also take a look at exhibit.

HE 2010-02-02: I use the following procedures to save/load an array in/from a file:
proc sarray {filename arrayname} {
        upvar $arrayname name
        set fid [open $filename w]
        foreach index [lsort [array names name]] {
                regsub -all -- {\n} [list $index $name($index)] {\n} tmp
                puts $fid $tmp
        }
        close $fid
        return
}
proc larray {filename arrayname} {
        upvar $arrayname name
        set fid [open $filename r]
        while {![eof $fid]} {
                gets $fid zeile
                if {$zeile eq {}} {
                        continue
                }
                regsub -all -- {\\n} $zeile "\n" tmp
                array set name $tmp
        }
        close $fid
        return
}

Casteele - 2016-06-24 23:22:39

Re: Saving/loading arrays to/from a file: I often see many people post these kind of code snippets, but they do not think them through. What happens if one of the array elements is actually file channel? A socket? A Tk window? An object? You will be saving the string representation of these things, rather than the thing itself, which can and often does change between invocations. You might unintentionally save a file handle reference that when you reload the array from the file, it may be pointing to another file entirely, possibly even a critical file. I've seen people write system programs which clobber /etc/passwd by doing this kind of thing. Especially when someone else modifies your code for their own needs, without realizing that you've put code in place that does this sort of thing.

As I try to put almost all my "global" data inside a single global array, thus avoiding having too many individual variable in global scope, saving an array with dynamic state information, such as open file handles, etc, would introduce many potentially nasty bugs. The only solution to this problem is to write code which knows how to handle each piece of data, and can safely (de)serialize it when needed. (Using object-orientated code helps a lot here!) It's a lot of extra programming, but shouldn't a programmer already be completely aware of the data they're operating on, and how to operate on it?

If you absolutely must use data-type agnostic code (generic programming), then look in to programming techniques which are better suited to it, such a using OO Classes, STL libraries, etc.


See also edit