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
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?
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 |
|______________________________________________________________________|
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
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
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
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
http://mini.net/cgi-bin/wikit/596.html
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