To operate on each element of a list, returning a modified list various languages have explicit constructs.
In Perl there's map:
perl -e 'my @a = (1..4); print join(q( ), map { $_ * $_ } @a)'
1 4 9 16
In Python there're list comprehensions:
>>> a = (1,2,3,4)
>>> [el*el for el in a]
[1, 4, 9, 16]
What's the most efficient way to do this in Tcl? I can come up with the usual foreach loop.
set l {}
foreach i {1 2 3 4} {
lappend l [expr $i * $i]
}
puts $l
1 4 9 16
Is this the fastest way?
Regarding mem efficiency this builds up a second list, one by one. If I don't need the list permanently is there a more efficient way?
And, finally, is there something that's shorter? I couldn't find infos here or in the http://wiki.tcl.tk
Answer:
As Donal Fellows has answered, most importantly for speed tests, things should be wrapped in a proc {} since Tcl then can optimize. For Tcl, a "map" function is discussed as a future enhancement. With this hint and further searching I found http://wiki.tcl.tk/12848
The most efficient method is this:
set idx 0
foreach item $theList {
lset theList $idx [expr {$item * $item}]
incr idx
}
If the list is short (e.g., a few hundred elements) the cost of allocating a new list is minimal though, so you can use this (simpler) version instead:
foreach item $theList {
lappend newList [expr {$item * $item}]
}
Note that the foreach
command is only fast if placed in a procedure (or lambda expression or method) and expressions are only fast if placed in {
braces}
. Also, don't speculate, measure: take care to use the time
command to find out how fast your code really is.
Well, there is something shorter (using the tcllib struct::list package), but not necessarily faster.
package require struct::list
puts [struct::list mapfor x $data { expr {$x * $x} }]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With