How can I make a string of n 1's in tcl? - tcl

I need to make a string of n 1's in tcl where n is some variable, how can I do this nicely?
At the moment I'm doing this but there must be a better way.
set i 1
set ones 1
while {$i < $n} {
set ones 1$ones
incr i}
In python I'd write "1"*n.

Solution 1:[Simple Solution]
set n 10
puts "[string repeat "1" $n]" ;# To display output on console
set output_str [string repeat "1" $n] ;# To get output in variable
Solution 2:
You have to append "one" inside string n number of times, where n is number of ones you want in string.
set n 10
set i 0
set ones 1
set output_str ""
while {$i < $n} {
append output_str $ones
incr i
}
Output,
puts $output_str ;#Gives output 1111111111

There is a built in string command to do this:
% set n 10
10
% string repeat "1" $n
1111111111
%

Related

To add preceding digits in a list in Tcl

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.

tcl to add numbers in columns till pattern mismatches

Hi I need to add numbers in a column till pattern matches and then to start adding numbers after pattern matches, for example:
start 1
start 2
start 3
pattern
start 4
start 5
start 6
I need to have sum as 6 till pattern and 15 after pattern separately, i tried regexp start but it adds all the numbers in 2nd column irrespective of 'pattern', i know sed works, but i need in tcl-regexp only
With minimal change to your current code and your current attempt/method to reach the desired outcome, this is what I suggest:
set sum1 0
set sum2 0
set ind 0
set skip true
while {![eof $file]} {
# Notice the change of $x to x here
gets $file x
if {[regexp start $x]} {
set ind [lindex $x 1]
# Depending on $skip, add the number to either sum1 or sum2
if {$skip == "true"} {
set sum1 [expr $sum1 + $ind]
} else {
set sum2 [expr $sum2 + $ind]
}
}
if {[regexp pattern $x]} {
set skip "false"
}
}
puts $sum1
puts $sum2
Though, I would use the following to make things a bit simpler:
set sum 0
while {[gets $file x] != -1} {
# if there line has "pattern, then simply print the current sum, then resets it to zero
if {[regexp pattern $x]} {
puts $sum
set sum 0
} elseif {[regexp {start ([0-9]+)} $x - number]} {
# if the line matches 'start' followed by <space> and a number, save that number and add it to the sum
# also, I prefer using incr here than expr. If you do want to use expr, brace your expression [expr {$sum+$ind}]
incr sum $number
}
}
# puts the sum
puts $sum

For loop increment by a non-integer in TCL

I want to implement the following C code in TCL:
Float power_pitch = 8
float offset = 7.5
float threshold = 100
for(i=power_pitch+offset ; i<= threshold ; i += power_pitch)
I want to implement above forloop in TCL. I have tried the following code in TCL:
set power_pitch 8
set offset 7.5
set threshold 100
for { set i [expr $power_pitch + $offset] } { $i <= $threshold } { incr i $power_pitch}
but when I execute above code I get the following error:
expected integer but got "15.5 "
while executing incr i $power_pitch
Could you help me to implement above forloop in TCL?
The incr command only works with integers. Otherwise, use:
set i [expr {$i + $power_pitch}]
The for command itself won't mind. (Be aware of float rounding issues; they're not Tcl-specific, but can hit with anything that isn't an integer multiple of a power of 2…)
Donal has already provided the answer to the question, I'd just like to make an observation in two points about the for command.
for is very nearly free-form
while an integral counting loop is a typical use of for, it's by no means the only option
The for command has the synopsis
for start test next body
where start, next, and body are command strings (i.e. appropriate as an argument to eval; they can be empty, contain single commands, or be full scripts) and test is a boolean expression string (i.e. appropriate as an argument to expr and evaluating to something that is or can be coerced into a boolean value).
Usually, start is used to set up for test and body, and next is supposed to bring the state incrementally closer to having test return a false value, but that's just a convention, not a requirement. The following are perfectly valid (but rather smelly) invocations:
for {set n 0 ; puts -nonewline X} {[incr n] < 5} {puts -nonewline X} {
puts -nonewline [string repeat - $n]
}
for {set f [open foo.txt] ; set n 0} {$n >= 0} {puts $line} {
set n [chan gets $f line]
}
Give for any combination of command strings and boolean expression, and it will run. It might execute its body forever or not even once, but it will run. Don't limit yourself to for {set i 0} {$i < 10} {incr i} {...} invocations, that's 1950s thinking.
Even if you just want to use it for counting loops, there are still lots of options, for instance:
for {set i 0} {$i < $limit} {incr i} {...} ;# simple increment
for {set i 0} {$i < $limit} {incr i $n} {...} ;# stepping increment/decrement
for {set i 0} {$i < $limit} {incr i $i} {...} ;# doubling increment
for {set i 0} {$i < $limit} {set i [expr {...}]} {...} ;# arbitrary change
Free your mind, the rest will follow.
Documentation: chan, expr, for, incr, open, puts, set, string

expected integer but got "floating point number" error

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.

how to increment variable by 0.5 in using for loop?

for {set i 0} {$i < 5} {incr i} {
puts "I inside first loop: $i"
}
Is it possible to increment i by .5 instead of 1 ?
Now the above code is providing below output:
i inside first loop: 0
i inside first loop: 1
i inside first loop: 2
i inside first loop: 3
i inside first loop: 4
but I need something like this:
I inside first loop: 0
I inside first loop: .5
I inside first loop: 1
... so on
Tcl's incr command only handles integer values. The recommended way of getting a loop value that steps by some fractional value is to use a integer loop counter and then compute the fractional value from it:
for {set i_int 0} {$i_int < 5} {incr i_int} {
set i [expr {$i_int * 0.5}]
puts "I inside first loop: $i"
}
This is important when the fractional step is not a simple multiple of a power of two; while 0.5 can be represented exactly in binary floating point arithmetic (it's 2-1 after all) 0.1 can't (just as 1/3 can't be written exactly in a finite number of decimal places).
By default, incr increments by 1 unit when no specific number is mentioned.
incr i 2
will increment i by 2 on each iteration.
incr i -1
will decrement i by 1 on each iteration.
You can thus change the number to be whatever you need it to be.
The only problem is that you can only increment by an integer. So you'll have to use something else for the 0.5. You can use expr perhaps?
for {set i 0} {$i < 5} {set i [expr {$i+0.5}]} {
puts "I inside first loop: $i"
}
EDIT: Actually, Donal's answer is better since it doesn't have the rounding errors :)
for {set i 0} {$i < 5} {incr i} {
puts "I inside first loop: [expr $i*0.5]"
}