How foreach loop in perl works with arrays in perl - perl

this program should execute three times but is executing only twice.
Can anyone explain how this foreach loop will work in perl.
#!/usr/bin/perl
use strict;
use warnings;
my #arr=("sandeepr", "vijay","vikas");
for my $i( #arr)
{
print #arr;
my $b=pop(#arr);
print "\n $b";
}

perlsyn:
If any part of LIST is an array, foreach will get very confused if you add or remove elements within the loop body, for example with splice. So don't do that.
As confused as this makes Perl, you appear to be even more confused. What are trying to do? Print the elements in reverse order? If so, you could use
for my $ele (reverse #arr) {
print("$ele\n");
}
or
for my $i (1..#arr) {
my $ele = $arr[-$i];
print("$ele\n");
}
or
while (#arr) {
my $ele = pop(#arr);
print("$ele\n");
}

Related

Perl: Printing out the file where a word occurs

I am trying to write a small program that takes from command line file(s) and prints out the number of occurrence of a word from all files and in which file it occurs. The first part, finding the number of occurrence of a word, seems to work well.
However, I am struggling with the second part, namely, finding in which file (i.e. file name) the word occurs. I am thinking of using an array that stores the word but don’t know if this is the best way, or what is the best way.
This is the code I have so far and seems to work well for the part that counts the number of times a word occurs in given file(s):
use strict;
use warnings;
my %count;
while (<>) {
my $casefoldstr = lc $_;
foreach my $str ($casefoldstr =~ /\w+/g) {
$count{$str}++;
}
}
foreach my $str (sort keys %count) {
printf "$str $count{$str}:\n";
}
The filename is accessible through $ARGV.
You can use this to build a nested hash with the filename and word as keys:
use strict;
use warnings;
use List::Util 'sum';
while (<>) {
$count{$word}{$ARGV}++ for map +lc, /\w+/g;
}
foreach my $word ( keys %count ) {
my #files = keys %$word; # All files containing lc $word
print "Total word count for '$word': ", sum( #{ $count{$word} }{#files} ), "\n";
for my $file ( #files ) {
print "$count{$word}{$file} counts of '$word' detected in '$file'\n";
}
}
Using an array seems reasonable, if you don't visit any file more than once - then you can always just check the last value stored in the array. Otherwise, use a hash.
#!/usr/bin/perl
use warnings;
use strict;
my %count;
my %in_file;
while (<>) {
my $casefoldstr = lc;
for my $str ($casefoldstr =~ /\w+/g) {
++$count{$str};
push #{ $in_file{$str} }, $ARGV
unless ref $in_file{$str} && $in_file{$str}[-1] eq $ARGV;
}
}
foreach my $str (sort keys %count) {
printf "$str $count{$str}: #{ $in_file{$str} }\n";
}

perl code for creating incremental arrays in for loop

I want to create arrays using for loop when it satisfy the particular condition. Such that it must create arrays say #a1 #a2 #a3 #a4 ... and so on . i have tried the method given below. But, i am not able to do so. Can you plz help
#/bin/usr/perl -w
use strict;
my $i;
my $m=0;
for ($i=0 ; $i<10 ; $i++ ) {
$a$m[$i]=$i;
}
$m++;
print #a1;
print #a2;
i have tried this way of creating arrays but it is not doing so.
Create a 2d array.
#!/bin/usr/perl -w
use strict;
use Data::Dumper qw( Dumper );
my #a;
my $n = 0;
for my $m (0..1) {
for my $i (0..9) {
$a[$m][$i] = $n++;
}
}
print(Dumper(\#a));
Why it's stupid to use a variable as a variable name

Why does escaping of # disappear when read from an array?

I have a string,
my $element="abc#$def"
I escape # using,
$element=~s/#/\\#/g;
It is printed as: abc\#$def, which is perfect.
Next part of the code is:
push(#arr,$element);
foreach $val (#arr)
{
print $val;
}
And the value printed within the foreach loop is: abc#$def.
Why is # not escaped here? And how can I retain the escaping?
You're not quite showing us everything. To get your claimed result, I had to create the variable $def initialized as shown below. But, when I do that, I get the result you expect, not the result you show.
$ cat xx.pl
use strict;
use warnings;
my $def = '$def';
my $element = "abc#$def";
$element =~ s/#/\\#/g;
print "$element\n";
my #arr;
push(#arr, $element);
foreach my $val (#arr)
{
print $val;
print "\n";
}
$ perl xx.pl
abc\#$def
abc\#$def
$
This was tested with Perl 5.14.1 on MacOS X 10.6.8, but I don't think the behaviour would vary with any other version of Perl 5.
Given this, can you update your question to show a script similar to mine (in particular, with both use strict; and use warnings;) but which produces the result you show?
With something like this:
$element=~s/#/\\#/g;
You have to escape the \
Edit
this code works on my machine as you expect:
use strict;
use warnings;
use Data::Dumper;
my $element='abc#$def';
my #arr;
$element=~s/#/\\#/g;
print $element."\n";
push(#arr,$element);
foreach my $val (#arr)
{
print $val;
}

Perl looping through a hash produces strange value

I'm using Perl to parse the output from objdump. I have the following code:
#!/usr/bin/perl
%count = {};
while (<>) {
if (/^\s+[[:xdigit:]]+:\s+[[:xdigit:]]+\s+([a-z]+).+$/) {
++$count{"$1"};
}
}
while (($key, $val) = each %count) {
print "$key $val\n";
}
In the resulting output, most parts are okay like this:
strhib 2
strcc 167
stmlsda 4
swivc 21
ldmlsia 4
But there is one strange line:
HASH(0x8ae2158)
What's going on here? I expect $1 to be a string, and ++$count{"$1"} should be perfectly fine.
Thank you.
So the correct code should be:
#!/usr/bin/perl
use strict;
my %count;
while (<>) {
if (/^\s+[[:xdigit:]]+:\s+[[:xdigit:]]+\s+([a-z]+).+$/) {
++$count{"$1"};
}
}
while (my ($key, $val) = each %count) {
print "$key $val\n";
}
If you had use warnings; you would have seen: "Reference found where even-sized list expected". Instead of
%count = {};
you should have said
my %count;
What you wrote was equivalent to this:
%count = ({} => undef);
That is, you initialized your hash with an empty hashref as a key with no associated value. The hashref stringified to "HASH(0x8ae2158)" (the number may change). To clear out a hash, you use parens () not braces {}. Braces construct a hash reference.
Even short programs like this should start with:
use strict;
use warnings;
The bugs you catch will be your own. :-)
The warnings pragma is preferred to the -w switch because it acts lexically. See What's wrong with -w and $^W in perllexwarn.

Why does my Perl max() function always return the first element of the array?

I am relatively new to Perl and I do not want to use the List::Util max function to find the maximum value of a given array.
When I test the code below, it just returns the first value of the array, not the maximum.
sub max
{
my #array = shift;
my $cur = $array[0];
foreach $i (#array)
{
if($i > $cur)
{
$cur = $i;
}
else
{
$cur = $cur;
}
}
return $cur;
}
Replace
my #array = shift;
with
my #array = #_;
#_ is the array containing all function arguments. shift only grabs the first function argument and removes it from #_. Change that code and it should work correctly!
Why don't you want to use something that works?
One of the ways to solve problems like this is to debug your data structures. At each step you print the data you have to see if what you expect is actually in there. That can be as simple as:
print "array is [#array]\n";
Or for complex data structures:
use Data::Dumper;
print Dumper( \#array );
In this case, you would have seen that #array has only one element, so there it must be the maximum.
If you want to see how list assignment and subroutine arguments work, check out Learning Perl.
You can write the function as:
#!/usr/bin/perl
use strict; use warnings;
print max(#ARGV);
sub max {
my $max = shift;
$max >= $_ or $max = $_ for #_;
return $max;
}
However, it would be far more efficient to pass it a reference to the array and even more efficient to use List::Util::max.