Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

comments? new tcllib module: listutil

32 views
Skip to first unread message

Glenn Jackman

unread,
Sep 16, 2001, 6:47:36 PM9/16/01
to
Anyone care to comment on the following code? It a tentative new
tcllib module, "listutil", containing:

lassign list varname ?varname ...?
- an implementation of the TclX lassign

lsearchx ?-all? ?mode? list pattern
- extending lsearch with an "-all" option to return all
matching indices

pop listVarName ?number?
- return the last number of elements from a list, while
removing them from the list

push listVarName element ?element ...?
- add the elements to the end of the list

shift listVarName ?number?
- return the first number of elements from a list, while
removing them from the list

unshift listVarName element ?element ...?
- add the elements to the beginning of the list


############################################################
namespace eval ::listutil {
namespace export lassign lsearchx pop push shift unshift

# exported procs
proc lassign {list args} {}
proc lsearchx {args} {}
proc pop {listVarName number} {}
proc push {listVarName args} {}
proc shift {listVarName number} {}
proc unshift {listVarName args} {}

# helpers
proc K {x y} {set x}
proc _lsearchx_all_notglob {args} {}
proc _lsearchx_all_glob {args} {}
}

package provide listutil 0.1

#
# lassign list var ?var...?
#
# Assign successive elements of a list to specified variables. If there are
# more variable names than fields, the remaining variables are set to the empty
# string. If there are more elements than variables, a list of the unassigned
# elements is returned. For example,
# lassign {dave 100 200 {Dave Foo}} name uid gid longName
# Assigns name to ``dave'', uid to ``100'', gid to ``200'', and longName to
# ``Dave Foo''.
#

proc ::listutil::lassign {list args} {
if {[llength $args] == 0} {
return -code error "wrong # args: lassign list varname ?varname ...?"
}
foreach varName $args {
upvar $varName _tmp_$varName
lappend vars _tmp_$varName
}
foreach $vars $list {break}
return [lrange $list [llength $vars] end]
}

#
# lsearchx - extend [lsearch] to return all matching indices
#
# lsearchx ?-all? lsearch_arguments ...
#
# see also http://purl.org/tcl/home/man/tcl8.4/TclCmd/lsearch.htm
#
# Returns: a list of indices, or -1 if no matching elements found.
#

proc ::listutil::lsearchx {args} {
set all [regexp {^-a(ll?)?$} [lindex $args 0]]
if {$all} {shift args}
# Try to find the first match.
# Let the Tcl core test for syntax errors.
if {[set code [catch {eval lsearch $args} result]] != 0} {
regsub lsearch $result {&x ?-all?} result
return -code $code $result
}
# if we get here, [lsearch] is OK with $args
if {$all && ($result != -1)} {
set pattern [pop args]
set list [lindex [pop args] 0]
switch -regexp -- $args {
{-s(o(r(t(ed?)?)?)?)?} -
{-e(x(a(ct?)?)?)?} -
{-r(e(g(e(xp?)?)?)?)?} {
# this is NOT glob-style matching
set result [_lsearchx_all_notglob $list $pattern $args $result]
}
default {
# optimization for -glob matching
set result [_lsearchx_all_glob $list $pattern]
}
}
}
return $result
}

proc ::listutil::_lsearchx_all_notglob {list pattern lsearch_args first} {
set result [list $first]
set nremoved [expr {1 + $first}]
shift list $nremoved
while {[set index [eval lsearch $lsearch_args [list $list] $pattern]] != -1} {
lappend result [expr {$nremoved + $index}]
incr index
shift list $index
incr nremoved $index
}
}

proc ::listutil::_lsearchx_all_glob {list pattern} {
set i 0
foreach element $list {
lappend tmp($element) $i
incr i
}
set result [list]
foreach matching_element [array names tmp $pattern] {
set result [concat $result $tmp($matching_element)]
}
return [lsort -integer $result]
}


proc ::listutil::shift {listName {num 1}} {
if {$num > 0} {
upvar $listName list
incr num -1
set elements [lrange $list 0 $num]
set list [lreplace [K $list [set list {}]] 0 $num]
return $elements
}
}

proc ::listutil::pop {listName {num 1}} {
if {$num > 0} {
upvar $listName list
set idx [expr {[llength $list] - $num}]
set elements [lrange $list $idx end]
set list [lreplace [K $list [set list {}]] $idx end]
return $elements
}
}

proc ::listutil::unshift {listName args} {
upvar $listName list
set list [eval linsert [list $list] 0 $args]
}

proc ::listutil::push {listName args} {
upvar $listName list
set list [concat $list $args]
}

--
Glenn Jackman

Darren New

unread,
Sep 16, 2001, 7:25:05 PM9/16/01
to
> shift listVarName ?number?
> - return the first number of elements from a list, while
> removing them from the list

You could call this one "dequeue" and ....

> unshift listVarName element ?element ...?
> - add the elements to the beginning of the list

... call this "enqueue" if you didn't want to sound like Perl.


> # lsearchx - extend [lsearch] to return all matching indices

> # Returns: a list of indices, or -1 if no matching elements found.

I suspect this will be just as useful and with far fewer special cases
to consider while calling if you had it return an empty list if there
were no matches.

I.e., I could do
foreach index [lsearchx -all ...] {
...
}
without having to test if the result is -1 first. If I want the
equivalent of testing if it's minus one, a test for an empty result is
just as affective.

Other than that, it looks quite useful. Perhaps adding at least one
level of "keyed lists" would be useful also.

--
Darren New
San Diego, CA, USA (PST). Cryptokeys on demand.
Who is this Dr. Ibid anyway,
and how does he know so much?

Don Porter

unread,
Sep 17, 2001, 11:56:07 AM9/17/01
to
Glenn Jackman <gle...@nortelnetworks.com> wrote:
> Anyone care to comment on the following code? It a tentative new
> tcllib module, "listutil", containing:

Can you comment on what it provides that is not already provided
by struct::queue and/or struct::stack already in tcllib? If
there's really new data structure behavior here, then how about
adding it to the "struct" package?

--
| Don Porter Mathematical and Computational Sciences Division |
| donald...@nist.gov Information Technology Laboratory |
| http://math.nist.gov/~DPorter/ NIST |
|______________________________________________________________________|

lvi...@yahoo.com

unread,
Sep 17, 2001, 12:09:16 PM9/17/01
to

According to Glenn Jackman <gle...@nortelnetworks.com>:
:Anyone care to comment on the following code?

I wonder if http://mini.net/cgi-bin/nph-wikit/43.html contains
any useful additions, thoughts, or alternatives - I've always
thought that http://tcllib.sf.net/ would be a great place to add
things like this.


--
--
"I know of vanishingly few people ... who choose to use ksh." "I'm a minority!"
<URL: mailto:lvi...@cas.org> <URL: http://www.purl.org/NET/lvirden/>
Even if explicitly stated to the contrary, nothing in this posting

Andreas Kupries

unread,
Sep 17, 2001, 12:51:34 PM9/17/01
to

"Glenn Jackman" <gle...@nortelnetworks.com> wrote in message
news:9o3a68$4qi$1...@bcarh8ab.ca.nortel.com...

> Anyone care to comment on the following code? It a tentative new
> tcllib module, "listutil", containing:

No comments on the code per se, but some general notes:

There is a C "listx" at http://www.purl.org/net/akupries/tcltk.html
Tom Wilkason <tom.wi...@home.com> did some additional work on this.

See also the Wiki http://mini.net/tcl/43.html (or
http://mini.net/tcl/2?List)
and the TIPs 57 and 58
http://www.purl.org/tcl/tip/57.html
http://www.purl.org/tcl/tip/58.html

--
Andreas Kupries <andr...@ActiveState.com>
Developer @ http://www.ActiveState.com


Glenn Jackman

unread,
Sep 17, 2001, 12:49:55 PM9/17/01
to
Don Porter <d...@clover.cam.nist.gov> wrote on [17 Sep 2001 15:56:07 GMT]:
>Glenn Jackman <gle...@nortelnetworks.com> wrote:
>> Anyone care to comment on the following code? It a tentative new
>> tcllib module, "listutil", containing:
>
>Can you comment on what it provides that is not already provided
>by struct::queue and/or struct::stack already in tcllib? If
>there's really new data structure behavior here, then how about
>adding it to the "struct" package?

What is new is a Tcl-only implementation of the TclX lassign, and
an extended lsearch procedure, lsearchx, which returns a list of
all matching indices, not merely the first.

As for the push/pop/... procs in listutil, it is true that they
add nothing to what is available in tcllib, and in fact are less
robust. However, as I look at the struct package, I notice that
it could use a deque (double-ended queue) structure. Also
would-be-nice would be to allow queues and stacks to "import" an
existing list "whole", as opposed to pushing each element of that
list.

--
Glenn Jackman

Glenn Jackman

unread,
Sep 17, 2001, 1:10:30 PM9/17/01
to
lvi...@yahoo.com wrote on [17 Sep 2001 16:09:16 GMT]:
>I wonder if http://mini.net/cgi-bin/nph-wikit/43.html contains
>any useful additions, thoughts, or alternatives - I've always
>thought that http://tcllib.sf.net/ would be a great place to add
>things like this.

I agree. There's also tons of good stuff listed at
http://mini.net/tcl/54.html. That page was last updated over two
years ago, so maybe the ball can get rolling again...

--
Glenn Jackman

Phil Ehrens

unread,
Sep 17, 2001, 1:44:22 PM9/17/01
to

Mike Jacobson

unread,
Sep 17, 2001, 4:15:01 PM9/17/01
to
"Glenn Jackman" <gle...@nortelnetworks.com> wrote in message news:<9o3a68$4qi$1...@bcarh8ab.ca.nortel.com>...
> Anyone care to comment on the following code?

How about we add ldelete (it seems to get used a lot but never makes
it into the show) to listutil.

proc ldelete { list value } {
set ix [lsearch -exact $list $value]
if {$ix >= 0} {
return [lreplace $list $ix $ix]
} else {
return $list
}
}

Mike Jacobson

0 new messages