Uninitialized value in join or string and uninitialized value in numeric gt when using perl script - perl

I have some problems running the code:
When I run the above code it shows the following:
Is it an error or not? How to make the code show only the results without the other lines.

Please post actual code samples (see the "code" button above) rather than screen shots. With screen shots anyone who actually wants to run your code has to type it in again, making it that much harder for them to help you.
That said, your messages are, strictly speaking, not errors but warnings. In this case Perl is warning you that you did not initialize subscripts 10-19 of your array #b4. How to suppress the warning depends on whether it is important to you that your array contain uninitialized cells.
My preference would be to eliminate the uninitialized values by replacing $b4[20] = "last"; with push #b4, "last";.
But if you need the array to contain the uninitialized cells, you can suppress the warning by no warnings 'uninitialized';. I recommend enclosing the pragma and the lines that warn in curly brackets to limit the scope of the pragma:
{
no warnings 'uninitialized';
print "b4: #b4\n";
my $z = reduce ...
print "New max index: $z\n";
}
Because you are requiring at least Perl 5.10 you can replace print ... "\n"; with say ...;.

Please don't post images of code. If we want to help you, it means we need to retype your code rather than copying and pasting.
Luckily, your problem is obvious without needing to run your code.
You create and populate your array, #b4 with these two lines of code:
my #b4 = qw( zero one two three four five six seven eight nine );
$b4[20] = "list";
This creates an array with some strings (in elements 0-9 and 20) and some undefined values (in elements 10-19).
You then display the contents of the array using print(). This accounts for the first ten warnings in your output - as Perl tries to print every element of the array and ten of them contain undef.
You then use the reduce() function on the array and that produces the rest of your warnings - as Perl tries to compare elements using > and many of the elements are undefined.
It's hard to suggest a good fix here without understanding a lot more about what your code is actually trying to do. One idea might be to replace the undefined elements with zeroes.
#b4 = map { $_ // 0 } #b4;
But that might have effects on code that you haven't shown us.
Update: It would be interesting to hear why someone didn't like my answer.

Related

Perl subroutines

Here I fixed most of my mistakes and thank you all, any other advice please with my hash at this point and how can I clear each word and puts the word and its frequency in a hash, excluding the empty words.. I think my code make since now.
So you can focus on the key part of the algorithm, how about accepting input on STDIN and output to STDOUT. That way there's no argument checking, etc. Just a simple:
$ prog < words.txt
All you really need is a very simple algorithm:
Read a line
Split it into words
Record a count of the word
When done, display the counts
Here's a sample program
#! /usr/bin/perl -w
use strict;
my (%data);
while (<STDIN>) {
chomp;
my(#words) = split(/\s+/);
foreach my $word (#words) {
if (!defined($data{$word})) {
$data{$word} = 0;
}
$data{$word}++;
}
}
foreach (sort(keys(%data))) {
print "$_: $data{$_}\n";
}
Once you understand this and have it working in your environment, you can extend it to meet your other requirements:
remove non-alphabetic characters from each word
print three results per line
use input and output files
put the algorithm into a subroutine
I agree that starting with dave's answer would be more productive, but if you are interested in your mistakes, here is what I see:
You assign the return value of checkArgs to a scalar variable $checkArgs, but return an array value. It means that $checkArgs will always contain 2 (the size of the array) after this call (because the program dies if the number of arguments is not 2). It is not very bad since you do not use the value later, but why you need it at all in this case?
You open files and close them immediately without reading from them. Does not make sense.
Statement
while (<>)
reads either from standard output or from all files in the command line arguments. The latter variant is like what you want, but your second argument is the output file, not input. The diamond operator will try to read from it too. You have two options: a) use only one file name in the command line arguments, read the file with <>, use standard output for output, and redirect output to a file in shell; b) use
while(<$file1>)
instead, of course, before closing files. Option a) is the traditional Unix- and Perl-style, but b) provides for clearer code for beginners.
Statements
return $word;
and
return $str, $hash{$str};
return corresponding values on the first iterations of the loops, all other data remain unprocessed. In the first case, you should create a local array, store all $word in it and return the array as a whole. In the second case, you already have such local %hash, it is enough to return this hash. In both cases, you need should assign the return values of the functions not to scalars, but to an array and a hash correspondingly. Now, you actually lose all you data.

Perl - variable as hash key

I'm returning a hash from the subroutine
my %hash = %{subroutine()};
later on I want to use the hash element as follows
if (defined $hash{LEVEL_1_KEY}{LEVEL_2_KEY}){
.
.
.}
This works well.
But If I want to try to use same element with LEVEL_1_KEY coming from variable. It doesn't work.
e.g.
my $var = "LEVEL_1_KEY";
if (defined $hash{$var}{LEVEL_2_KEY}){
...
}
What am I doing wrong? Should I use some apostrophes, or quotes with $var? I tried several things, but no success yet.
Your code should work as written, so there's something left out of your code.
My first impulse is the use of defined. Checking with exists or defined is a red flag. It means your code is using trinary or even quadrary logic. True, false, defined and existence. Worse, they overlap: true is also defined; undefined is also false; existence combines with any of the others; and so on. There are valid uses for checking if a thing is defined, but casual use is confusing and error prone. It's very easy for a false value to sneak into a slot that's supposed to remain undefined. Consider changing the defined check to a truth check.
(The primary use of defined would be where 0 or '' is a valid value).
Here's general debugging ideas.
Does $var contain what you think it contains?
Print it out just before it is used.
Does $var really contain what you think it contains?
Print it out with quotes like print qq['$var'] to catch any trailing whitespace.
Does $var really really contain what you think it contains?
Is it coming from a filehandle? Could it contain special Unicode that looks like plain ASCII? Try print "Yes" if $var eq "LEVEL_1_KEY"
Are you sure you don't have single quotes around $var?
It's $hash{$var} right? Not $hash{'$var'}.
Does %hash contain what you think it contains?
Dump it out using Data::Dumper just before you use it.
Is that line of code even reached?
Print a print statement before the condition.
Does the condition block do anything?
Maybe the condition is working, but the code inside the block doesn't. Put a print statement inside the block just after the condition.
Just because it's defined doesn't mean it's true.
You're checking the value is defined, not true. It could be an empty string. It could be all spaces. It could be 0. Does the rest of the code want a defined value or a true value?
As a side note, you're somewhat better off leaving the return value from your subroutine as a hash reference, rather than dereferencing it. Dereferencing causes a temporary copy of the hash to be made which can use CPU and memory. How much impact this will really have depends on how big the hash is, and you should get used to working with references for general efficiency.
There's a typo in your code
if (defined $hash{LEVEL_1_KEY}{LEVEL_2_KEY){
should be
if (defined $hash{LEVEL_1_KEY}{LEVEL_2_KEY}){
Rest it works fine, you can check it here: http://ideone.com/QT36e4
Are you sure you are writing $var like you stated or are you taking the name from some file or STDIN?

regarding usage of arrow notation in perl

I've following two statements written in perl :
#m1 = ( [1,2,3],[4,5,6],[7,8,9] ); # It is an array of references.
$mr = [ [1,2,3],[4,5,6],[7,8,9] ]; # It is an anonymous array. $mr holds reference.
When I try to print:
print "$m1[0][1]\n"; # this statement outputs: 2; that is expected.
print "$mr->[0][1]\n"; #this statement outputs: 2; that is expected.
print "$mr[0][1]\n"; #this statement doesn't output anything.
I feel second and third print statements are same. However, I didn't any output with third print statement.
Can anyone let me know what is wrong with third print statement?
This is simple. $mr is a reference. So you use the Arrow Operator to dereference.
Also, if you would use use warnings; use strict;, you would have received a somewhat obvious error message:
Global symbol "#mr" requires explicit package name
$mr is a scalar variable whose value is a reference to a list. It is not a list, and it can't be used as if it was a list. The arrow is needed to access the list it refers to.
But hold on, $m1[0] is also not a list, but a reference to one. You may be wondering why you don't have to write an arrow between the indexes, like $m1[0]->[1]. There's a special rule that says you can omit the arrow when accessing list or hash elements in a list or hash of references, so you can write $mr->[0][1] instead of $mr->[0]->[1] and $m1[0][1] instead of $m1[0]->[1].
$mr holds a reference (conceptually similar to the address of a variable in compiled languages). thus you have an extra level of indirection. replace $mrwith $$mr and you'll be fine.
btw, you can easily check questions like these by browsing for tutorials on perldoc.
You said:
print "$m1[0][1]\n"; # this statement outputs: 2; that is expected.
print "$mr[0][1]\n"; #this statement doesn't output anything.
Notice how you used the same syntax both times.
As you've established by this first line, this syntax accesses the array named: #m1 and #mr. You have no variable named #mr, so you get undef for $mr[0][1].
Maybe you don't realizes that scalar $mr and array #mr have no relation to each other.
Please use use strict; use warnings; to avoid these and many other errors.

A better variable naming system?

A newbie to programming. The task is to extract a particular data from a string and I chose to write the code as follows -
while ($line =<IN>) {
chomp $line;
#tmp=(split /\t/, $line);
next if ($tmp[0] !~ /ch/);
#tgt1=#tmp[8..11];
#tgt2=#tmp[12..14];
#tgt3=#tmp[15..17];
#tgt4=#tmp[18..21];
foreach (1..4) {
print #tgt($_), "\n";
}
I thought #tgt($_) would be interpreted as #tgt1, #tgt2, #tgt3, #tgt4 but I still get the error message that #tgt is a global symbol (#tgt1, #tgt2, #tgt3, #tgt4` have been declared).
Q1. Did I misunderstand foreach loop?
Q2. Why couldn't perl see #tgt($_) as #tgt1, #tgt2 ..etc?
Q2. From the experience this is probably a bad way to name variables. What would be a preferred way to name variables that have similar features?
Q2. Why couldn't perl see #tgt($_) as #tgt1, #tgt2 ..etc?
Q2. From the experience this is probably a bad way to name variables. What would be a preferred way to name variables that have similar features?
I'll asnswer both together.
#tgt($_) does NOT mean what you hope it means
First off, it's an invalid syntax (you can't use () after an array name, perl interpeter will produce a compile error).
What you're trying to do is access distinct variables by accessing a variable via an expression resulting in its name (aka symbolic references). This IS possible to do; but is typically a bad idea and poor-style Perl (as in, you CAN but you SHOULD NOT do it, without a very very good reason).
To access element $_ the way you tried, you use #{"tgt$_"} syntax. But I repeat - Do Not Do That, even if you can.
A correct idiomatic solution: use an array of arrayrefs, with your 1-4 (or rather 0-3) indexing the outer array:
# Old bad code: #tgt1=#tmp[8..11];
# New correct code:
$tgt[0]=[ #tmp[8..11] ]; # [] creates an array reference from a list.
# etc... repeat 4 times - you can even do it in a smart loop later.
What this does is, it stores a reference to an array slice into a zeroth element of a single #tgt array.
At the end, #tgt array has 4 elements , each an array reference to an array containing one of the slices.
Q1. Did I misunderstand foreach loop?
Your foreach loop (as opposed to its contents - see above) was correct, with one style caveat - again, while you CAN use a default $_ variable, you should almost never use it, instead always use named variables for readability.
You print the abovementioned array of arrayrefs as follows (ask separately if any of the syntax is unclear - this is a mid-level data structure handling, not for beginners):
foreach my $index (0..3) {
print join(",", #{ $tgt[$index]}) . "\n";
}

Error using intermediate variable to access Spreadsheet::Read sheets

I'm no expert at Perl, wondering why the first way of obtaining numSheets is okay, while the following way isn't:
use Spreadsheet::Read;
my $spreadsheet = ReadData("blah.xls");
my $n1 = $spreadsheet->[1]{sheets}; # okay
my %sh = %spreadsheet->[1]; # bad
my $n2 = $sh{label};
The next to last line gives the error
Global symbol "%spreadsheet" requires explicit package name at newexcel_display.pl line xxx
I'm pretty sure I have the right sigils; if I experiment I can only get different errors. I know spreadsheet is a reference to an array not directly an array. I don't know about the hash for the metadata or individual sheets, but experimenting with different assumptions leads nowhere (at least with my modest perl skill.)
My reference on Spreadsheet::Read workings is http://search.cpan.org/perldoc?Spreadsheet::Read If there are good examples somewhere online that show how to properly use Spreadsheet, I'd like to know where they are.
It's not okay because it's not valid Perl syntax. The why is because that's not how Larry defined his language.
The sigils in front of variables tell you what you are trying to do, not what sort of variable it is. A $ means single item, as in $scalar but also single element accesses to aggregates such as $array[0] and $hash{$key}. Don't use the sigils to coerce types. Perl 5 doesn't do that.
In your case, $spreadsheet is an array reference. The %spreadsheet variable, which is a named hash, is a completely separate variable unrelated to all other variables with the same identifier. $foo, #foo, and %foo come from different namespaces. Since you haven't declared a %spreadsheet, strict throws the error that you see.
It looks like you want to get a hash reference from $spreadsheet->[1]. All references are scalars, so you want to assign to a scalar:
my $hash_ref = $spreadsheet->[1];
Once you have the hash reference in the scalar, you dereference it to get its values:
my $n2 = $hash_ref->{sheets};
This is the stuff we cover in the first part of Intermediate Perl.