set mylist {this is a test for the lsplit Tcl command} lsplit $mylist x {[string length $x] < 4} left right puts $left puts $rightMore information inside the comments.
# Split a list in two sub-lists of elements passing, or not passing # a given test. # # The signature is the following: # # lsplit listValue variable expression ?firstListVar secondListVar? # # We call the sublist of elements passing the test left-list, # and the sublist of elements not passing the test right-list. # # If lsplit is called with three arguments, # it returns [list $left-list $right-list] # # If lsplit is called with additional two arguments (five in total), # the last two arguments are used as variable names where # to store the left-list, and the right-list, and the command # returns [list [llength $left-list] [llength $right-list]]. # # This function was inspired by the Joy programming language # 'split' primitive. # # Copyright (C) 2004 Salvatore Sanfilippo # All the Rights reserved. # ################################################################################ # # This software is copyrighted by Salvatore Sanfilippo. # The following terms apply to all files associated with the software # unless explicitly disclaimed in individual files. # # The authors hereby grant permission to use, copy, modify, distribute, # and license this software and its documentation for any purpose, provided # that existing copyright notices are retained in all copies and that this # notice is included verbatim in any distributions. No written agreement, # license, or royalty fee is required for any of the authorized uses. # Modifications to this software may be copyrighted by their authors # and need not follow the licensing terms described here, provided that # the new terms are clearly indicated on the first page of each file where # they apply. # # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR # MODIFICATIONS. # # GOVERNMENT USE: If you are acquiring this software on behalf of the # U.S. government, the Government shall have only "Restricted Rights" # in the software and related documentation as defined in the Federal # Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you # are acquiring the software on behalf of the Department of Defense, the # software shall be classified as "Commercial Computer Software" and the # Government shall have only "Restricted Rights" as defined in Clause # 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the # authors grant the U.S. Government and others acting in its behalf # permission to use and distribute the software in accordance with the # terms specified in this license. proc lsplit {list var expression args} { switch -- [llength $args] { 2 {upvar [lindex $args 0] left [lindex $args 1] right} 0 {} default { error [format %s%s "Wrong number of arguments. Try lsplit " \ "var expr ?leftListVar rightListVar?"] } } upvar $var x set left {} set right {} foreach e $list { # We take a copy of the element in 'e', # because 'expresion' is evaluated in a context # that may change the value of $x set x $e if {[uplevel expr [list $expression]]} { lappend left $e } else { lappend right $e } } if {![llength $args]} { list $left $right } else { list [llength $left] [llength $right] } }
RS has this version:
proc lsplit {list cond} { set yes {}; set no {} foreach el $list {if [$cond $el] {lappend yes $el} {lappend no $el}} list $yes $no } proc even x {expr {$x%2 ==0}} % lsplit {1 2 3 4} even {2 4} {1 3}
SS the RS's version is more functional, but the rationale for my lsplit semantic is that when there is already a defined tester function, like "even", you can still write:
% lsplit {1 2 3 4} x {[even $x]}That's a bit more complex, but still acceptable. On the other hand, often the test condition is simple, and the programmer don't want to define a procedure just for this. In such a case she can write:
% lsplit {1 2 3 4} x {$x&1}Without to have to deal with anonymous functions and lambda implementations.
RS has, over a long time, come to think that anonymous functions (lambdas) are the real functions, and names are just an added sugar to that...