Code Comments
Programming Forum and web based access to our favorite programming groups.For the need to write out the contents of an array to a file, I had a look into $tcl_library/parray.tcl and found two (minor) things: 1.) for finding the longest key, it traverses the *lsorted* list. Here, sorting is just a waste of cpu-cycles. (as opposed to sorting in the actual output-loop) 2.) I wonder, if it could be easily extended with a few options to puts the formatted text to a specified channel (rather than to hardcoded stdout), or evenmore: to just return the text.
Post Follow-up to this messageAndreas Leitgeb wrote: > 1.) for finding the longest key, it traverses the *lsorted* > list. Here, sorting is just a waste of cpu-cycles. > (as opposed to sorting in the actual output-loop) The efficient thing to do is to compute the list once (before the loop) and sort it then too. I've updated the HEAD to do this (I'm not going to backport the change on its own; it's just inefficiency in something which is best used only for debugging anyway). > 2.) I wonder, if it could be easily extended with a few options > to puts the formatted text to a specified channel (rather than > to hardcoded stdout), or evenmore: to just return the text. Any suggestions for a backward-compatible API change to do this? Donal.
Post Follow-up to this message"Donal K. Fellows" wrote: > > Andreas Leitgeb wrote: > > The efficient thing to do is to compute the list once (before the loop) > and sort it then too. I've updated the HEAD to do this (I'm not going to > backport the change on its own; it's just inefficiency in something > which is best used only for debugging anyway). > > > Any suggestions for a backward-compatible API change to do this? > > Donal. What about : parray -inline arrayName and parray -out $channel arrayName ? Regards, Arjen
Post Follow-up to this messageOn Fri, 3 Jun 2005, Arjen Markus wrote:
> "Donal K. Fellows" wrote:
>
> What about :
>
> parray -inline arrayName
>
> and
>
> parray -out $channel arrayName
>
> ?
This is not backwards compatible. Good for Tcl9, I guess. Until then,
parray array ?pattern=* ?channel=stdout??
Clumsy (forces channelwriters to specify pattern) but is compatible as
parray accepted only one parameter. Using empty channel name just returns
list of formatted lines (true channel can't have empty name?). At Tcl9
backward compatibility can be broken by adding true switches to [parray].
Memorywasting when printing huge arrays is reduced by wasting clock cycles
to check channel at every iteration. Diff is against 8.5a2 parray.tcl
(I failed to find those cvs head differences).
13c13
< proc parray {a {pattern *}} {
---
> proc parray {a {pattern *} {chan {stdout}}} {
24a25
> set olst {}
27c28,32
< puts stdout [format "%-*s = %s" $maxl $nameString $array($name)]
---
> if {$chan eq {}} {
> lappend olst [format "%-*s = %s" $maxl $nameString $array($name)
]
> } else {
> puts $chan [format "%-*s = %s" $maxl $nameString $array($name)]
> }
28a34
> if {$chan eq {}} {return $olst}
Just an idea.
--
-Kaitzschu
s="TCL ";while true;do echo -en "\r$s";s=${s:1:${#s}}${s:0:1};sleep .1;done
Post Follow-up to this messageKaitzschu wrote: > > > This is not backwards compatible. Good for Tcl9, I guess. Until then, > > parray array ?pattern=* ?channel=stdout?? > > Clumsy (forces channelwriters to specify pattern) but is compatible as > parray accepted only one parameter. Using empty channel name just returns > list of formatted lines (true channel can't have empty name?). At Tcl9 > backward compatibility can be broken by adding true switches to [parray]. > > Memorywasting when printing huge arrays is reduced by wasting clock cycles > to check channel at every iteration. Diff is against 8.5a2 parray.tcl > (I failed to find those cvs head differences). > Oh, I forgot about the pattern ... Yes, you are right, that makes it less trivial. However, would it be disastrous to be not 100% compatible: - If an option is given, then it must start with a "-" - Patterns often have * or ? in them So my proposal would preclude: - array names that start with a "-" - patterns without wild-cards - (and possibly only the combination) Regards, Arjen
Post Follow-up to this messageAt 2005-06-03 04:13AM, Andreas Leitgeb <avl@gamma.logic.tuwien.ac.at> wrote:
> For the need to write out the contents of an array to a file,
> I had a look into $tcl_library/parray.tcl and found two (minor)
> things:
>
> 1.) for finding the longest key, it traverses the *lsorted*
> list. Here, sorting is just a waste of cpu-cycles.
> (as opposed to sorting in the actual output-loop)
>
> 2.) I wonder, if it could be easily extended with a few options
> to puts the formatted text to a specified channel (rather than
> to hardcoded stdout), or evenmore: to just return the text.
I once rewrote parray for my own purposes, to add an optional channelID
like puts:
########################################
##################################
# parray ?channelId? arrayName ?pattern?:
#
# based on:
# RCS: @(#) $Id: parray.tcl,v 1.3 1998/09/14 18:40:03 stanton Exp $
#
# Copyright (c) 1991-1993 The Regents of the University of California.
# Copyright (c) 1994 Sun Microsystems, Inc.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
proc parray args {
switch -exact -- [llength $args] {
1 { set chan stdout ; set a $args ; set pattern * }
2 {
# is the first arg a channel?
if {[catch {tell [lindex $args 0]} out] == 0} {
# yep
foreach {chan a} $args break
set pattern *
} else {
# nope
foreach {a pattern} $args break
set chan stdout
}
}
3 { foreach {chan a pattern} $args break }
default { error "wrong # args: should be \"[lindex [info level 0] 0] ?channe
lID? arrayName ?pattern?\"" }
}
upvar 1 $a array
if {![array exists array]} {
error "\"$a\" isn't an array"
}
set maxl 0
foreach name [array names array $pattern] {
if {[string length $name] > $maxl} {
set maxl [string length $name]
}
}
set maxl [expr {$maxl + [string length $a] + 2}]
foreach name [lsort [array names array $pattern]] {
set nameString [format %s(%s) $a $name]
puts $chan [format "%-*s = %s" $maxl $nameString $array($name)]
}
}
--
Glenn Jackman
NCF Sy
min
glennj@ncf.ca
Post Follow-up to this messageAndreas Leitgeb wrote: > For the need to write out the contents of an array to a file, > I had a look into $tcl_library/parray.tcl and found two (minor) > things: > > 1.) for finding the longest key, it traverses the *lsorted* > list. Here, sorting is just a waste of cpu-cycles. > (as opposed to sorting in the actual output-loop) > > 2.) I wonder, if it could be easily extended with a few options > to puts the formatted text to a specified channel (rather than > to hardcoded stdout), or evenmore: to just return the text. > If it does not need to be pretty (i.e. you want to save it to read in again later): puts $outChan [list array set arrayName [array get arrayName]] -- +--------------------------------+---------------------------------------+ | Gerald W. Lester | "The man who fights for his ideals is | | Gerald.Lester@cox.net | the man who is alive." -- Cervantes | +--------------------------------+---------------------------------------+
Post Follow-up to this messageKaitzschu wrote:
> < proc parray {a {pattern *}} {
That's about what I was thinking as well.
Donal.
Post Follow-up to this messageDonal K. Fellows <donal.k.fellows@manchester.ac.uk> wrote: > Kaitzschu wrote: > That's about what I was thinking as well. yes, looks quite ok. If chan is provided and empty (or special "return"), then it should collect and finally [return], rather than write it out...
Post Follow-up to this messageGerald W. Lester <Gerald.Lester@cox.net> wrote:
> If it does not need to be pretty (i.e. you want to save it to read in agai
n
> later):
> puts $outChan [list array set arrayName [array get arrayName]]
sure, for reading it in later, this is *the* way to do it.
In my case it was for a human reader to check if the array contained
the right things. The only requirement was, that the code should fit
in one or two lines and only at those places where something was
watched, which excluded writing up my own procedure.
Instead, I wrote:
set xx ""; foreach {k v} [array get myarr] {append xx "x($k)=$v\n"}
exec echo $xx > /tmp/avl-logfile
Even shorter would have been:
exec echo "myarr:\n[join [array get myarr] "\n"]\n" > /tmp/avl-logfile
But I could afford two lines, and I found it worth the luxury :-)
(why "shelling"(I know, no /bin/sh involved!) out to echo?
Because that takes fewer chars than open/puts/close would. :-)
Flattened lists (like what is returned by array get, or listified dicts)
are a bit tough to handle in Tcl. The only command that really handles
them sensibly is foreach with multiple variables.
I propose some extension for [join] (and, unless the echo here
is mostly negative or nonexistent, I'll likely tip it up later):
example first:
set list {1a 1b 1c 2a 2b 2c 3a 3b 3c}
puts >[join $list . , \n]<
>1a.1b,1c
2a.2b,2c
3a.3b,3c<
join _now_ accepts the list and _one_ (optional) string.
join would *then* accept the list and an *arbitrary number* of
strings which would be cycled through.
Post Follow-up to this messagePowered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.