views:

92

answers:

2

I would like to get all elements following a particular index of a list. This could be written as:

set foo {0 1 2 3 4 5 6 <...> n}
puts [lrange $foo 1 [llength $foo]]

However, it seems like a waste to compute the length of the list. It would be nice if the last argument to lrange was optional and omitting it meant to continue until the end of the list, but, alas that is not the case today.

Is there some other way of doing this efficiently in Tcl without computing the length of the list?

+7  A: 

You can use "end" in place of "[llength $foo]"

So...

puts [lrange $foo 1 end]

Jeff

Jeff Godfrey
In addition, you can access a specific element offset from "end" via things like:end-1 (2nd to last element)end-7 (8th to last element)Jeff
Jeff Godfrey
It's worth noting that this behavior is documented in the man pages. The lrange man page points you to the string man page, saying that the indexes work just like string index. On the string man page it explicitly states "end" is a valid index (and also mentions end-1, etc)
Bryan Oakley
+3  A: 

Jeff answered your actual question well. That being said, there is one thing worth noting. Getting the length of a list (that's actually a list under the hood) is of O(1), meaning it takes no real time. The length of the list itself is stored with the metadata, and isn't recalculated. The only real cost is the overhead of a function call. Using "end" is probably still faster, just not as much as you might have thought.

But "actually a list under the hood", I mean that the interpreter is currently treating it as a list (there a deeper explanation, but not worth going into here). Since you are using [lrange] on the value, the interpreter must convert it's internal to a list... so you're pretty much guaranteed the O(1) behavior of [llength].

RHSeeger
nice explanation
glenn jackman