Unset elements from an array in tcl - arrays

I am creating an array in TCL for which the input should be a series of numbers. The first
two elements of the array is supposed to carry the information for deletion of the elements present inside the array. First element must carry the index of the element
occupying the array where the deletion should start with and the second element
carry the index of the element occupying the array up to which the deletion should
progress.
I am kind of new to TCL and tried the below code but facing errors saying cant read array (numarray here). Some help in fixing it is most welcome.
#! /user/bin/tclsh
puts "Enter sequence count: ";
gets stdin count;
puts "\nEnter the numbers: ";
for {set i 0} {$i < $count} {incr i} {
gets stdin numarray($i);
}
set delstart $numarray(0);
puts "Starting index: " $numarray(0);
set delend $numarray(1);
for {set $i $delstart} {$i < $delend} {incr $i} {
unset numarray($i);
}
puts "\nNumber array after deletion :";
foreach $i [array names numarray] {
puts "$numarray($i)";
}

You have multiple problems throughout the code due to one underlying issue.
Generally speaking, when you want the value of a variable, use the $ in front.
When you are writing to a variable, use the variable name.
I will use one line from your code as an example:
for {set $i $delstart} {$i < $delend} {incr $i} {
As it is, the command would be interpreted as:
for {set 12 $delstart} {$i < $delend} {incr 12} {
12 is a valid variable name, but not the one you are using.
Should be:
for {set i $delstart} {$i < $delend} {incr i} {
Only the test $i < $delend needs the value.

Related

Parametrized population of a string in bash from 1 to n

Is there an easy way to populate a dynamic string with a size parameter?
lets say, we have:
Case N=1:
echo "Benchmark,Time_Run1" > $LOGDIR/$FILENAME
however, the run variable is parametric and we want to have all Time_Runs from 1 to n:
Case N=4:
echo "Benchmark,Time_Run1,Time_Run2,Time_Run3,Time_Run4" > $LOGDIR/$FILENAME
and the generic solution should be this form:
Case N=n:
echo "Benchmark,Time_Run1,...,Time_Run${n}" > $LOGDIR/$FILENAME
Is there a way to do that in a single loop rather than having two loops, one looping over n to generate the Run${n} and the other, looping n times to append "Time_Run" to the list (similar to Python)? Thanks!
Use a loop from 1 to $n.
{
printf 'Benchmark'
for ((i = 1; i <= $n; i++)); do
printf ',Time_Run%d' $i
done
printf '\n'
} > $LOGDIR/$FILENAME
One way to populate the output string with a single loop is:
outstr=Benchmark
for ((i=1; i<=n; i++)); do
outstr+=",Time_Run$i"
done
It can also be done without a loop:
eval "printf -v outstr ',%s' Time_Run{1..$n}"
outstr="Benchmark${outstr}"
However, eval is dangerous and should be used only in cases where there is no reasonable alternative. This is not such a case. See Why should eval be avoided in Bash, and what should I use instead?.

Perl Program to Count Two Character Frequencies

I am trying to find two character strings in a text file and print them and their frequencies out.
#!/usr/bin/perl
#digram finder
use strict; use warnings;
#finds digrams in a file and prints them and their frequencies out
die "Must input file\n" if (#ARGV != 1);
my ($file) = #ARGV;
my %wordcount;
open (my $in, "<$file") or die "Can't open $file\n";
while (my $words = <$in>){
chomp $words;
my $length = length($words);
for (my $i = 0; $i<$length; $i++){
my $duo = substr($words, $i; 2);
if (not exists $wordcount{$duo}){
$wordcount{$duo} = 1;
}
else {
$wordcount{$duo}++;
}
}
}
foreach my $word (sort {$wordcount{$b} cmp $wordcount{$a}} keys %wordcount){
print "$word\t$wordcount{$duo}\n";
}
close($in);
First I set the text file to a string $words.
Then, I run a for loop and create a substring $duo at each position along $words
If $duo doesn't exist within the hash %wordcount, then the program creates the key $duo
If $duo does exist, then the count for that key goes up by 1
Then the program prints out the digrams and their frequencies, in order of decreasing frequency
When I try to run the code, I get the error message that I forgot to declare $word on line 17 but I do not even have the string $word. I am not sure where this error message is coming from. Can someone help me find where the error is coming from?
Thank you
My best guess is that you actually have $word instead of $words; a typo. If the compilation found the symbol $word in the text then it's probably there.
However, I'd also like to comment on the code. A cleaned up version
while (my $words = <$in>) {
chomp $words;
my $last_duo_idx = length($words) - 2;
for my $i (0 .. $last_duo_idx) {
my $duo = substr($words, $i, 2);
++$wordcount{$duo};
}
}
my #skeys = sort { $wordcount{$b} <=> $wordcount{$a} } keys %wordcount;
foreach my $word (#skeys) {
print "$word\t$wordcount{$word}\n";
}
This runs correctly on a made-up file. (I sort separately only so to not run off of the page.)
Comments
Need to stop one before last in the line, and substr starts from 0; thus -2
One almost never needs a C-style loop
There is no need here to test for existence of a key. If it doesn't exist it is autovivified (created), then incremented to 1 with ++; otherwise the count is incremented.
To sort numerically use <=>, not cmp
Typos:
substr($words, $i; 2) needs a , not ;, so substr($words, $i, 2)
$wordcount{$duo} in print should be $wordcount{$word}.
I am not sure about naming: why is a line of text called $words?

Counting how many numbers greater than 5 in a given array

I am having an error saying that prototype not terminated at filename.txt line number 113 where as line number 113 belongs to a different program which is running successfully.
sub howmany(
my #H = #_;
my $m = 0;
foreach $x (#H) {
if ( $x > 5 ) {
$m +=1;
}
else {
$m +=0;
}
}
print "Number of elements greater than 5 is equal to: $m \n";
}
howmany(1,6,9);
The sub keyword should be followed by { } not ( ) (if you define a simple function), that's why the error
prototype not terminated
After this, always start with : use strict; use warnings;
Put this and debug your script, there's more errors.
Last but not least, indent your code properly, using an editor with syntax highlighting, you will save many time debugging
The error is due to parenthesis.
Never do $m += 0; As you actually load processor for nothing. Of course it's not gonna be visible on such a small function, but...
sub howmany {
my $m = 0;
foreach (#_) {
$m++ if ($_ > 5);
}
print "Number of elements greater than 5 is equal to: $m \n";
}
howmany(1,6,9);

Tracking of number of elements in an array iterated?

Is there any way that number of elements iterated in an for loop can be traced in perl:
Like using special variables:
#arrayElements = (2,3,4,5,6,7,67);
foreach (#arrayElements) {
# Do something
# Want to know how may elements been iterated after
# some n number of elements processed without using another variable.
}
Either just count as you go:
my $processed = 0;
foreach my $element (#array_elements) {
...
++$processed;
}
or iterate over the indexes instead:
foreach my $index (0..$#array_elements) {
my $element = $array_elements[$index];
...
}
In perl5 v12 and later, you can use the each iterator:
while(my($index, $element) = each #array_elements) {
...;
}
However, the more portable solution is to iterate over the indices, and manually access the element, as shown by ysth.
In any case, the number of elements that were visited (including the current element) is $index + 1.
You may get the number of elements in an array as
my $num = #arrayElements;
print $num;
OR
my $num = scalar (#arrayElements);
print $num;
OR
my $num = $#arrayElements + 1;
print $num;
And for finding number of elements iterated, we can use the below code :
my $count = 0; #initially set the count to 0
foreach my $index(#arrayElements)
{
$count++;
}
print $count;

Perl Modification of non creatable array value attempted, subscript -1

I have a Perl-Script, which executes a recursive function. Within it compares two elements of a 2dimensional Array:
I call the routine with a 2D-Array "#data" and "0" as a starting value. First I load the parameters into a separate 2D-Array "#test"
Then I want to see, if the array contains only one Element --> Compare if the last Element == the first. And this is where the Error occurs: Modification of non creatable array value attempted, subscript -1.
You tried to make an array value spring into existence, and the subscript was probably negative, even counting from end of the array backwards.
This didn't help me much...I'm pretty sure it has to do with the if-clause "$counter-1". But I don't know what, hope you guys can help me!
routine(#data,0);
sub routine {
my #test #(2d-Array)
my $counter = $_[-1]
for(my $c=0; $_[$c] ne $_[-1]; $c++){
for (my $j=0; $j<13;$j++){ #Each element has 13 other elements
$test[$c][$j] = $_[$c][$j];
}
}
if ($test[$counter-1][1] eq $test[-1][1]{
$puffertime = $test[$counter][4];
}
else{
for (my $l=0; $l<=$counter;$l++){
$puffertime+= $test[$l][4]
}
}
}
#
#
#
if ($puffertime <90){
if($test[$counter][8]==0){
$counter++;
routine(#test,$counter);
}
else{ return (print"false");}
}
else{return (print "true");}
Weird thing is that I tried it out this morning, and it worked. After a short time of running he again came up with this error message. Might be that I didn't catch up a error constellation, which could happen by the dynamic database-entries.
Your routine() function would be easier to read if it starts off like this:
sub routine {
my #data = #_;
my $counter = pop(#data);
my #test;
for(my $c=0; $c <= $#data; $c++){
for (my $j=0; $j<13;$j++){ #Each element has 13 other elements
$test[$c][$j] = $data[$c][$j];
}
}
You can check to see if #data only has one element by doing scalar(#data) == 1 or $#data == 0. From your code snippet, I do not see why you need to copy the data to passed to routine() to #test. Seems superfluous. You can just as well skip all this copying if you are not going to modify any of the data passed to your routine.
Your next code might look like this:
if ($#test == 0) {
$puffertime = $test[0][4];
} else {
for (my $l=0; $l <= $counter; $l++) {
$puffertime += $test[$l][4];
}
}
But if your global variable $puffertime was initialized to zero then you can replace this code with:
for (my $l=0; $l <= $counter; $l++) {
$puffertime += $test[$l][4];
}

Resources