I try to write a very simple program in TCL using list.
Below is the list
list { 1 2 3 4 5 6 1.5 7 }
Below is my code
set sum 0
for {set i 0} {$i < [llength $list]} {incr i} {
incr sum [lindex $list $i]
}
puts $sum
On executing the above program I am getting the below error due to floating point value of 1.5 in the list
expected integer but got "1.5"
(reading increment)
invoked from within
"incr sum [lindex $list $i]"
I searched on internet and could not find anything relevant.
Please advise how do I handle the floating point value?
While using incr command, variable must have value that can be interpreted as a an integer. See tcl wiki.
If variable is a non-integral real number, [incr] could not be used, but [set] could:
set sum 0
for {set i 0} {$i < [llength $list]} {incr i} {
set sum [expr {$sum + [lindex $list $i]}]
}
puts $sum
Omsai's answer should solve your problem, but a cleaner solution is to use foreach:
set sum 0
foreach n $list {
set sum [expr {$sum + $n}]
}
puts $sum
Summing up a list of numeric values can also be done with the ::tcl::mathop::+ command:
::tcl::mathop::+ {*}$list
This looks more complicated that it is. The + command isn't available in the regular namespace, so you need to specify where it comes from (the ::tcl::mathop namespace). The command expects to get each operand as a separate argument, so if they are in a list you need to expand that list using the {*} prefix.
foreach and the various mathop commands are documented here: foreach, mathop.
(Note: the 'Hoodiecrow' mentioned in the comments is me, I used that nick earlier.)
Tcl gives an error if you will try
incr a 1.5
you have to change the logic.
clearly you want to add all the numbers in the list. and answers are easy and many. But i will give you the shortest way:
set l { 1 2 3 4 5 6 1.5 7 }
set sum [expr [join $l +]]
NO LOOPING REQUIRED.
Related
Could someone help me to understand why the below code hangs (i.e. stuck in an endless loop) in Xcelium simulator, and what should be the correct one?
for {set i 0} {$i < 2} {incr $i} { puts "i is $i"; }
set i 0
while {$i < 2} { puts "i is $i"; incr $1; }
The result for either for or while loop above is just an endless: i is 0
incr takes a variable name as input argument, so it should be incr i.
incr $i increments instead the variable 0. What happens if the variable does not exist depends on Tcl version. From the manual page:
Starting with the Tcl 8.5 release, the variable varName passed to incr may be unset, and in that case, it will be set to the value increment or to the default increment value of 1.
I am trying to incorporate the preceding digits in a numerical list, say 1-14, before the list 15-43.
I am using TCL for writing my code.
I am expecting the list should be 1,2,3,....43, instead the list is coming to be 15,16,17,...43.
I have tried to incorporate the missing numbers as follows:
set nres2 ""
set x 0
set y [lindex $nres $x]
while {$x < [llength $nres]} {
set i [lindex $nres $x]
while {$y < $i} {
lappend nres2 $y
incr y
}
incr x
incr y
}
This will incorporate missing numbers within a list like, if a list 15,16,17...,43 do not have numbers like 18, 22, 34, etc., it will incorporate these numbers in a separate list named as nres2.
But, I cannot include the preceding numbers of a corresponding list.
Any comments/suggestions will be greatly helpful.
Thanks in advance...
Prathit Chatterjee
I would change the y at the start:
set nres2 ""
set x 0
set y 1
while {$x < [llength $nres]} {
set i [lindex $nres $x]
while {$y < $i} {
lappend nres2 $y
incr y
}
incr x
incr y
}
With nres as 4 6 8 9, nres2 becomes 1 2 3 5 7, which is what I think you are trying to get.
Jerry posted already the immediate fix, but you may think about general improvements over your implementation using pairwise comparisons:
proc printMissings1 {lst} {
set b [lrepeat [lindex $lst end] 0]
foreach i $lst {
lset b $i 1
}
lsearch -exact -integer -all $b 0
}
printMissings1 $nres
lrepeat is used to create a Tcl list (array) of [llength $nres] elements.
lset is used to mark the elements whose indices correspond to values in the given range.
lsearch is used to return the indices of the elements left unmarked, which correspond to the missing values.
In following code in TCL I cannot seem evaluate the variable "a"
I'm evaluating x and y, in the same For Loop I have a IF statement that is checking for a range between x and y.
If valid then I'd like to perform some more calculations within the IF condition.
Every thing is fine up to the IF condition, but I cant seem to evaluate "a".
I'm trying to set "a" to the value of "y" for all the values within the range $min <= $x && $x <= $max
I would kindly request the experts to highlight the mistake.
for {set i 0} {$i < $lenght} {incr i} {
set x [expr ([lindex $cal1 $i])*$offset]
set y [expr ((cal2)/2) ]
if {$min <= $x && $x <= $max } {
puts "is Active"
set a [lindex $y $i]
puts a = $a
}
}
There is a lot that seems problematic in your code.
In the first line, you use the variable lenght. Tcl doesn't care about spelling, but if you don't have such a variable (you might possibly have a length variable instead) you will get an error.
In the invocation expr ([lindex $cal1 $i])*$offset] you have an unnecessary parenthesis but no braces around the expression (the braces aren't mandatory but should be there unless there is a very good reason to omit them). Also: "offset" usually means something you add to, not multiply with, another value. The invocation expr {[lindex $cal1 $i] * $offset}] would be better.
The variable y is used as a list argument to lindex later on, but it's created as a scalar variable. Also, your expression divides a string (or rather, an invalid bareword) with 2. Maybe you meant lappend y [expr {$cal2 / 2}]? If you use lappend, each value will be added to the end of an existing list, or as the first element of a new list if y doesn't exist. This is usually what one wants, but it means that the list y should be reset using set y [list] or set y {} before entering the loop, to get rid of elements added earlier, if any.
puts a = $a won't work, because if there are more than one argument to puts they are expected to be the flag -nonewline and/or a channel id to send the output to. Maybe you meant puts "a = $a".
Brain Teaser: I self originated this question, but stuck completely.
I want to create all possible combination of all characters, but of all possible lengths. Suppose, [a-z] combination of 1 length, then [a-z] combination of 2 length, and so on till the maximum length achieved.
this could be very easily done by iterative looping.
Example for 3 length:
proc triples list {
foreach i $list {
foreach j $list {
foreach k $list {
puts [list $i $j $k]
}
}
}
}
But, it should solve using less loops (looping needs to be dynamic)
set chars "abcdefghijklmnopqrstuvwxyz"
set chars [split $chars ""]
set complete_length [llength $chars]
set start 0
set maximum_length 15
while {1} {
if {$start > $maximum_length} {
break
}
for {set i [expr $maximum_length-$start]} {$i >= 0} {incr i -1} {
# dump combinations
}
incr start
}
In this chunk, what algorithm or method i should apply? Any kind of suggestions/help/code will be appreciated.
Sry, this is not an answer, but hopefully some interesting discussion anyway:
The word "combinations" is often used way too generally, so it can be interpreted in many different ways. Let's say that you have a source list of 26 different elements, the english letters, and you want to pick 3 of them and combine in a 3 element destination list:
Can you always pick any letter from the source list, or do the elements disappear from it as you pick them? Either define "pick" (are the elements copied or moved during a pick), or define the set of source values (is there 1 of each of A-Z or an infinite amount of A-Z).
Does the order in the destination list matter? Is AHM considered to be the same combination as HAM? Define "combine".
If you have a list where not all elements are different, e.g. {2 10 10 64 100}, you have even more possibilities. Define your set of values.
Your first example prints permutations, not combinations. If that's what you want, the easiset way is a recursive procedure. Combinations are more complicated to generate.
EDIT:
I wrote this procedure for a Project Euler program. It picks all the elements, but maybe you can modify it to pick n. It takes a command prefix as argument, so you don't have to store all permutations.
package require Tcl 8.5.0
proc forEachPerm {list cmdPrefix} {
_forEachPerm {} $list $cmdPrefix
}
proc _forEachPerm {head list cmdPrefix} {
if {![llength $list]} {
{*}$cmdPrefix $head
} else {
for {set i 0} {$i < [llength $list]} {incr i} {
_forEachPerm [concat $head [lrange $list $i $i]] [lreplace $list $i $i] $cmdPrefix
}
}
}
# example use:
forEachPerm {a b c} {apply {{list} {puts [join $list]}}}
For example, in Perl, to get a sequential array of numbers from 1 to 10, you could simply do:
#myArray = (1 .. 10);
The two periods serve as shorthand for this operations instead of making a for loop or writing the whole thing out manually. Other languages I've used have something similar also.
Does a similar shorthand exist in Tcl?
You can define the method:
proc fillArray {a b} {
eval return \[list $a [string repeat "\[incr a\] " [incr b -$a]]\]
}
And use it as:
set myArray [fillArray 1 10]
You even can beautify the call of procedure to make it look as in perl. For that just redefine unknown procedure:
rename unknown __unknown
proc unknown {args} {
if {[llength $args] == 3} {
lassign $args a op b
if {[string is integer $a] && $op == ".." && [string is integer $b]} {
return [fillArray $a $b]
}
}
return [uplevel __unknown {*}$args]
}
After that you can write just simple as:
set myArray [1 .. 10]
:)
Not quite this one, but
% package require struct::list
1.6.1
% struct::list iota 10
0 1 2 3 4 5 6 7 8 9
Also search this for the "iota" keyword to see how this can be done using a one-liner.
With the exception of expressions (which are their own little language) Tcl has no operators and is always a strictly prefix-driven language. This means that there isn't such a convenient shorthand for doing loops. On the other hand, there's nothing particularly special about Tcl's standard commands (apart from some minor efficiency details that don't matter here) so making your own is no problem:
proc .. {from to} {
if {$from >= $to} {
for {set i $from} {$i <= $to} {incr i} {lappend out $i}
} else {
for {set i $from} {$i >= $to} {incr i -1} {lappend out $i}
}
return $out
}
puts [.. 1 10]; # --> “1 2 3 4 5 6 7 8 9 10”
You can fake infix operators by using an unknown handler (as in GrAnd's answer) but that's really quite slow by comparison with the above.
No, a similar shorthand does not exist in tcl.
If you really want shorthand, you can create your own command that looks almost the same. For example:
proc : {start ignore end} {
set result []
for {set i $start} {$i <= $end} {incr i} {
lappend result $i
}
return $result
}
puts "from 1 to 10: [: 1 .. 10]"