[Klaus Saalfeld] A function `lselect` is proposed that selects a number of items from a list and returns them as a new list. In contrast to known `lindex` with multiple indices `lselect` doesn't operate on nested lists but on flat lists. The returned list contains the items in the same order as specified with the indices argument. ** Using a list argument ** ====== # Returns from the specified list one or more elements identified by given indices. # The first element in list is given by index 0, the last element of list is given by "end". # An optional negative offset (e.g. "end-1") can be used to specify elements relative to the end of list. # The list to operate on is passed by value. proc lselect {value indices} { set result {} if {0 != [llength $value]} { foreach index $indices { if {0 == [string compare -length 3 $index end]} { set index [expr ([llength $value] - 1) [string range $index 3 end]] } if {($index >= 0) && ($index < [llength $value])} { lappend result [lindex $value $index] } } } return $result } ====== Some examples: ====== % lselect {car house tiger penguin} {end-1 1 end 0} tiger house penguin car % lselect {banana pineapple orange} 1 pineapple % lselect {tcl is great} {-1 17 end-8} % lselect {more awesome stuff} {1 1 1} awesome awesome awesome ====== Many list operations are a special case of `lselect`. For example: * `lindex $x $n` corresponds to `lselect $x $n`. * `lrange` means selecting a consecutive range of items from a list `lselect` can be combined with known `lsearch` to extract items from a list that match a given pattern: ====== % set fruits {banana ananas pineapple orange apple} % lselect $fruits [lsearch -all $fruits a*] ananas apple ====== `lselect` is moreover useful to implement stack or buffer like behavior with lists or to shuffle lists. ** Using args ** [Larry Smith] Might I suggest the slightly less verbose: ====== # Returns from the specified list one or more elements identified by given indices. # The first element in list is given by index 0, the last element of list is given by "end". # An optional negative offset (e.g. "end-1") can be used to specify elements relative to the end of list. # The list to operate on is passed by listval. proc lselect {listval args} { set result {} if {[llength $listval]>0} { foreach index $args { lappend result [lindex $listval $index] } } return $result } ====== Which has (mostly) the same results. The comparisons against "end" are unneeded since lindex takes care of them itself. Using args means the indices does not have to itself be a list. ====== % lselect {car house tiger penguin} end-1 1 end 0 tiger house penguin car % lselect {banana pineapple orange} 1 pineapple % lselect {tcl is great} -1 17 end-8 {} {} {} % lselect {more awesome stuff} 1 1 1 awesome awesome awesome ====== [Klaus Saalfeld] Hi Larry and thanks for your input. As far as I can see the results differ when an invalid index is given: Using this variant `lappend` concats empty values to the resulting list (which I think is not a good feature). At first I throught you're right concerning "end" handling which might be delegated to `lindex`. But then I thought `lselect` might get problems dealing with empty list items. This is because you can't tell whether `lindex` has not found an item or the item was found but is empty (in which case `lselect` should return it). The result also differs if `args` is given but empty: ====== % lselect {a b c} {} {a b c} ====== ** See also ** * [Additional list functions]