print first row of a 2d Array in Perl - arrays

I have the below code and I'm attempting to print out only the first row of this 2d array
# how many columns
for (my $c = 0; $c <= $#list[0]; $c++) {
print $list[0][$c]."\n";
the data should be something like
[0] => "ID,Cluster,Version"
[1] => "2,32,v44"
The Error:
syntax error at ./connect_qb.pl line 107, near "$#list["
syntax error at ./connect_qb.pl line 107, near "++) "
Execution of ./connect_qb.pl aborted due to compilation errors.

$list[0]
is a reference to an array, so the array is
#{ $list[0] }
so the last element of that array is
$#{ $list[0] }
so you'd use
for my $c (0 .. $#{ $list[0] }) {
print "$list[0][$c]\n";
}
or
for (#{ $list[0] }) {
print "$_\n";
}

You should avoid c-style for loops. Here's one way to do it.
use strict;
use warnings;
use feature qw(say);
my #a = (["ID","Cluster","Version"], ["2","32","v44"]);
say for (#{$a[0]});
A slightly less confusing dereferencing:
...
my $ref = $a[0];
say for (#$ref);

Here is a simple one liner for that
print join(",",#{$list[0]}),"\n";

Try this:
for (my $c = 0; $c <= (scalar #{$list[0]}); $c++)
for the loop condition

Related

Comparing two strings line by line in Perl

I am looking for code in Perl similar to
my #lines1 = split /\n/, $str1;
my #lines2 = split /\n/, $str2;
for (int $i=0; $i<lines1.length; $i++)
{
if (lines1[$i] ~= lines2[$i])
print "difference in line $i \n";
}
To compare two strings line by line and show the lines at which there is any difference.
I know what I have written is mixture of C/Perl/Pseudo-code. How do I write it in the way that it works on Perl?
What you have written is sort of ok, except you cannot use that notation in Perl lines1.length, int $i, and ~= is not an operator, you mean =~, but that is the wrong tool here. Also if must have a block { } after it.
What you want is simply $i < #lines1 to get the array size, my $i to declare a lexical variable, and eq for string comparison. Along with if ( ... ) { ... }.
Technically you can use the binding operator to perform a string comparison, for example:
"foo" =~ "foobar"
But it is not a good idea when comparing literal strings, because you can get partial matches, and you need to escape meta characters. Therefore it is easier to just use eq.
Using C-style for loops is valid, but the more Perl-ish way is to use this notation:
for my $i (0 .. $#lines1)
Which will iterate over the range 0 to the max index of the array.
Perl allows you to open filehandles on strings by using a reference to the scalar variable that holds the string:
open my $string1_fh, '<', \$string1 or die '...';
open my $string2_fh, '<', \$string2 or die '...';
while( my $line1 = <$string1_fh> ) {
my $line2 = <$string2_fh>;
....
}
But, depending on what you mean by difference (does that include insertion or deletion of lines?), you might want something different.
There are several modules on CPAN that you can inspect for ideas, such as Test::LongString or Algorithm::Diff.
my #lines1 = split(/^/, $str1);
my #lines2 = split(/^/, $str2);
# splits at start of line
# use /\n/ if you want to ignore newline and trailing spaces
for ($i=0; $i < #lines1; $i++) {
print "difference in line $i \n" if (lines1[$i] ne lines2[$i]);
}
Comparing Arrays is a way easier if you create a Hashmap out of it...
#Searching the difference
#isect = ();
#diff = ();
%count = ();
foreach $item ( #array1, #array2 ) { $count{$item}++; }
foreach $item ( keys %count ) {
if ( $count{$item} == 2 ) {
push #isect, $item;
}
else {
push #diff, $item;
}
}
#Output
print "Different= #diff\n\n";
print "\nA Array = #array1\n";
print "\nB Array = #array2\n";
print "\nIntersect Array = #isect\n";
Even after spliting you could compare them as Array.

Foreach array with Perl

It seems my code cannot iterate over an array stored in a hash.
What did I miss ?
#!/usr/bin/env perl
use Data::Dumper;
my $data = {array => ['a', 'b', 'c']};
my #array = $data->{array};
print Dumper(#array); # It looks like $data->{array} is an array
print "Ref: ".ref($data->{array})."\n"; # And this array is indeed an array
foreach ($data->{array}) { print "$_\n"; } # But this doesn't work
foreach (#array) { print "$_\n"; } # Neither this one
# But with a regular array it works...
my #myNames = ('Larry', 'Curly', 'Moe');
foreach (#myNames) { print "$_\n"; }
My output:
$VAR1 = [
'a',
'b',
'c'
];
$VAR1 = 'a';
Ref: ARRAY
ARRAY(0x8002bcf8)
ARRAY(0x8002bcf8)
Larry
Curly
Moe
I am pretty confused with REF/SCALAR types. Sometime Perl takes values as references sometime not. In this case, because I get 'ARRAY' from the ref function, I guess $->{array} doesn't give me an array but a reference to the array.
I have also tried #$data->{array} without success.
$data->{array} is indeed an array reference.
To dereference it, use #{} on the reference
foreach (#{$data->{array}}) { print "$_\n"; }
Edit:
Or if you dont want to use {...} after #
my $arrayref = $data->{array};
foreach (#$arrayref ) { print "$_\n"; }

An elegant way of returning the index of the last non-zero element in Perl?

I find myself wanting to find the index of the last non-zero element in an array. So, given:
my #array = (0,0,5,9,0,0,0,7,0,3,0,0);
my $indexLastNonZero = insertElegantMethodHere(#array);
# expect $indexLastNonZero to be equal to 9;
I've done this:
for my $i (0 .. $#array) {
$indexLastNonZero = $i if $array[$i] != 0;
};
I works but somehow I can't help feel there must be a super elegant (smarter? nice? more efficient?) way of doing this in perl. I've looked into List::Utils but not found a nice way there and would like a non-core-module independent method.
Any thoughts?
Cheers
Use List::MoreUtils for such tasks:
use warnings;
use strict;
use List::MoreUtils;
my #array = (0,0,5,9,0,0,0,7,0,3,0,0);
print List::MoreUtils::lastidx { $_ } #array
Start at the end of the array and work backwards until you find a non-zero element:
my #array = (0,0,5,9,0,0,0,7,0,3,0,0);
my $i = $#array;
$i-- while $i >= 0 && $array[$i] == 0;
print "The last non-zero element is at index $i\n";
The $i >= 0 test is to guard against the edge case where all elements are zero. In that case the resulting value of $i is -1.
my #array = (0,0,5,9,0,0,0,7,0,3,0,0);
my ($indexLastNonZero) = grep $array[$_], reverse 0 .. $#array;
You could use List::Util, which is in core:
use strict;
use warnings;
use List::Util qw(first);
my #array = (0,0,5,9,0,0,0,7,0,3,0,0);
my $index = #array;
first { $index-- && $_ } reverse #array;
print "Last index that is non-zero: $index\n";
Destructive approach so take a copy of the array first:
my #array2 = #array;
while (!pop #array2) {} # Remove up to and including the last non-zero
print scalar #array2; # Size of remaining elements is index of last non-zero
sub last_true {
pop and return scalar #_ while #_;
undef;
}
my $index = last_true(#foo);

Perl Script -: Useless use of array element in void context at letter_counter.pl lin 38 and 44

this is first my perl script
http://bpaste.net/show/171137/
#!/usr/bin/perl
#This program will take a user's input and then count how many letters there are. Whereupon it will count the number of unique letters before printing all the data
#back to the user.
use strict;
use warnings;
#======================================================================================================================
# This section is to collect and spit back the input to the user.
#======================================================================================================================
print "\n\nHello, please enter a word, a phrase, or a sentence. Press Enter when you are done.\n";
my $input = <>; #Collecting the input from the user.
chomp $input; #Chomping, or removing, the \n from the end of the input.
print "\nYou typed -:[$input]\n";
#======================================================================================================================
#This section will find how many unique characters there are.
#======================================================================================================================
my #uniqueArray;
my #stringArray = split(// , $input);
my $x = 0;
my $string_max_index = $#stringArray;
for($stringArray[$x];$stringArray[$string_max_index];$x++)
{
my $found = 0;
my $test = $stringArray[$x];
my $y = 0;
for($uniqueArray[$y];$uniqueArray[$#uniqueArray];$y++)
{
if($test eq $uniqueArray[$y])
{
$found=1;
}
}
if($found eq 1)
{
$uniqueArray[$#uniqueArray] = $stringArray[$x];
}
}
#======================================================================================================================
# This section will determine how many ascii characters are in the $input variable and output the results of this
# program.
#======================================================================================================================
my $numOfLet = 0;
while ( $input ne "" )
{
$numOfLet = $numOfLet + 1;
chop $input
}
print "Total Characters -: $numOfLet";
print "Total of Unique Characters -: $#uniqueArray \n\n\n";
exit;
I was able to get rid of all the errors except for these two,
Useless use of array element in void context at letter_counter.pl line 38
Useless use of array element in void context at letter_counter.pl line 44
What is confusing me is that There is nothing at those lines, just the closing brackets for my for loop, which leads me to believe that the issue is an element I called in each for loop.
The initialization block of your for loop is the immediate culprit. Adjusting to something like this resolves the warning:
for(;$stringArray[$string_max_index];$x++)
Otherwise you're accessing a value, but doing... nothing with it? That's what the warning is for.
I spot a few other problems, though:
Your for loops are... a little funny, I don't know how else to put that.
Array length is usually easiest to read with the scalar keyword.
Adding members to an array is usually done with the push keyword.
Using the above in combination:
for(my $x = 0; $x < scalar #stringArray;$x++)
{
my $found = 0;
my $test = $stringArray[$x];
my $y = 0;
for (my $y = 0; !$found && $y < scalar #uniqueArray;$y++)
{
if($test eq $uniqueArray[$y])
{
$found=1;
}
}
unless ($found)
{
push #uniqueArray, $stringArray[$x];
}
}
If the above for loops don't look sensible to you, now is a good time to look up some tutorials.
This could be simplified with foreach loops:
foreach my $letter (#stringArray) {
...
}
Or with grep searches:
my $found = grep { $_ eq $letter } #uniqueArray;
But, in the particular case of counting unique values, it's often simplest to assign to a hash:
my %uniques;
$uniques{$_} = 1 for #stringArray;
my $num_uniques = scalar keys %uniques;
Combining all of that:
my #letters = split(//, $input); #split input into array of chars
my %uniques; #declare empty hash
$uniques{$_} = 1 for #letters; #set hash key for each char
my $num_letters = scalar #letters; #count entries in letter list
my $num_uniques = scalar keys %uniques; #count unique keys in letter hash
Exercise for the reader: adjust the above code so that it counts the number of times each character is used.
That's because #uniqueArray is empty...
Given this short example:
use strict;
use warnings;
my #arr;
my $t = 0;
for ($arr[$t]; $arr[$#arr]; $t++ ) {
print "no\n";
}
__OUTPUT__
Useless use of array element in void context at t.pl line 11.
You declare my #uniqueArray; at line 21 and never do anything with it...
Which also means how will this ever match at line 34?
if($test eq $uniqueArray[$y])
Again, #uniqueArray is an empty array.
To fix your script (although please look at rutter's hash suggestion), you can do the following. Remove:
my $x = 0;
my $y = 0;
Instead of using C-style loops, replace with the following:
for my $x (0 .. $string_max_index )
for my $y (0 .. $#uniqueArray)
Lastly, use the following:
if(!$found)
{
push #uniqueArray, $stringArray[$x];
}
Hope this helps!

2d arr explicitpackage

I've looked through several threads on websites including this one to try and understand why I am getting an undeclared variable error for my usage of my $line . Each element of the #lines array is an array of strings.
The error is in line 25 and 27 with the $line[$count] statement
use strict;
use warnings;
my #lines;
my #sizes;
# read input from stdin file into 2d array
while(<>)
{
push(#lines, my #tokens = split(/\s+/, $_));
}
# search through each array for largest sizes in
# corresponding elements
for (my $count = 0; $count <= 5; $count++)
{
push(#sizes, 0);
foreach my $line (#lines)
{
if(length($line[$count])>$sizes[$count])
{
$sizes[$count] = length($line[$count]);
}
}
}
I can post the full code if it is necessary, but I am pretty sure the error must be in here somewhere.
The problem is here:
push(#lines, my #tokens = split(/\s+/, $_));
Pushing one array into another just adds all elements to the first array. So you are making a really long one dimensional array.
To fix this, use brackets to make an array reference:
push #lines, [ split(/\s+/, $_) ]; #No need for a temp variable.
Also, to access the array reference, you have to de-reference it. Both of these syntaxes are options:
${$line}[$count];
$line->[$count];
I think the second syntax is more readable.
Update: Also, you could simplify your code if you keep track of the longest lengths while you go through the file:
use strict;
use warnings;
use List::Util qw/max/;
my #lines;
my #sizes = (0)x6;
while(<>)
{
push #lines, [ my #tokens = split ];
#sizes = map { max ( length($tokens[$_]), $sizes[$_] ) } 0..$#tokens;
}
Note: The Data::Dumper core module is an invaluable tool when working with complex data structures in Perl.
use Data::Dumper;
print Dumper #lines;
This will print out the complete structure of whatever variable you give it. That way you can see if you actually created what you thought you did.

Resources