Warning message in older perl version - arrays

I have the following code in my script:
while (my ($key, $value) = each #values) {
if ( $key < $arraySize-1) {
if ( $values[$key+1] eq "user") {
$endcon=1;
}
}
if ( ( $startcon == 1 ) && ( $endcon != 1 ) ) {
$UptimeString .= $value;
}
if ( $value eq "up") {
$startcon=1;
}
if ( $value eq "average:") {
$LoadMinOne=$values[$key+1];
}
}
While compiling it, in perl 5.14, I have no warnings, but in perl 5.10.1, I have this warning: Type of arg 1 to each must be hash (not private array) at ./uptimep.pl line 21, near "#values) "
Line 21 is while (my ($key, $value) = each #values) {
What does this mean?

As said in error message, each must have a hash for parameter, but you give it an array.
You could replace this line:
while (my ($key, $value) = each #values) {
by:
for my $key(0 .. $#values) {
my $value = $values[$key];
According to the doc each accepts array as parameter from perl 5.12.0

as it says, each expects a hash as an argument, not an array.
you can populate a hash first ( my %hash = #values; ) and use it as an argument ( while (my ($key, $value) = each %hash) ).

Related

Get array object data from exploded array fields in foreach loop

I'm trying to extract data from our JSON data based on given output fields, but I'm not getting a good result.
e.g.
Given fields that I want:
Array
(
[0] => id
[1] => name
[2] => email
[3] => optin_email
)
Those fields exist in my datastring, I want to export those to a CSV.
I can do this, hardcoded
foreach ($jsonString as $value) {
$row = [
$value->id,
$value->name,
$value->email,
$value->phone
];
print_r($row);
}
The above will give me the list/file I need. BUT, I want to make that dynamic based on the data in the array, so, fo rexample, when this is the Array:
Array
(
[0] => id
[1] => name
)
This should be my output:
foreach ($jsonString as $value) {
$row = [
$value->id,
$value->name
];
print_r($row);
}
So I need to dynamicly create the
$value->{var}
I have been trying forever, but I am not seeing it straight anymore.
Tried this:
$rowFields = '';
foreach ($export_datafields AS $v) {
$rowFields .= '$value->' . $v . ',';
}
$trimmed_row_fields = rtrim($rowFields, ',');
foreach ($jsonString as $value) {
$row = $trimmed_row_fields;
print_r($row);
}
And several variations of that:
foreach ($jsonString as $value) {
$row = [$trimmed_row_fields];
print_r($row);
}
Question is: how can I get
$value->VAR
as a valid array key when I only know the VAR name and need the prefixed $value-> object.
I ended up using the following code which works for me. If anybody still has the answer to my original question, please shoot. Always good to know it all.
header("Content-type: application/csv");
header("Content-Disposition: attachment; filename=$csvFileName");
header("Pragma: no-cache");
header("Expires: 0");
$new_row = implode(",", $export_datafields) . "\n";
foreach ($jsonString as $value) {
foreach ($export_datafields AS $v) {
$new_row .= $value->$v . ',';
}
$new_row = substr($new_row, 0, -1);
$new_row .= "\n";
}
echo $new_row;

filter file by unique and biggest value; combine two arrays into hash

I need to extract by unique genus (first part of the name of species) in one column but with by biggest number in another column in a CSV file when having multiples of the same name.
So if have multiple genus (same first name) then take the biggest number in the last column to select which will represent that genus.
I have extracted the information into arrays, but I am having trouble with combining the two in order to select. I was using
https://perlmaven.com/unique-values-in-an-array-in-perl
to help but I need to include biggest number in last column when have the same genus situation.
use strict;
use warnings;
open taxa_fh, '<', "$ARGV[0]" or die qq{Failed to open "$ARGV[0]" for input: $!\n};
open match_fh, ">$ARGV[0]_genusLongestLEN.csv" or die qq{Failed to open for output: $!\n};my #unique;
my %seen;
my %hash;
while ( my $line = <taxa_fh> ) {
chomp( $line );
my #parts = split( /,/, $line );
my #name = split( / /, $parts[3]);
my #A = $name[0];
my #B = $parts[5];
#seen{#A} = ();
my #merged = (#A, grep{!exists $seen{$_}} #B);
my #merged = (#A, #B);
#hash{#A} = #B;
print "$line\n";
}
close taxa_fh;
close match_fh;
Input example:
AB179735.1.1711,AB179735.1.1711,278983,Eucyrtidium hexagonatum,0,1600
AB179736.1.1725,AB179736.1.1725,278986,Pterocorys zancleus,0,1763
AB181888.1.1758,AB181888.1.1758,281609,Protoperidinium crassipes,0,1700
AB181890.1.1709,AB181890.1.1709,281610,Protoperidinium denticulatum,0,1800
AB181892.1.1738,AB181892.1.1738,281611,Protoperidinium divergens,0,1800
AB181894.1.1744,AB181894.1.1744,281612,Protoperidinium leonis,0,1500
AB181899.1.1746,AB181899.1.1746,281613,Protoperidinium pallidum,0,1600
AB181902.1.1741,AB181902.1.1741,261845,Protoperidinium pellucidum,0,1750
AB181904.1.1734,AB181904.1.1734,281614,Protoperidinium punctulatum,0,1599
AB181907.1.1687,AB181907.1.1687,281615,Protoperidinium thorianum,0,1600
AB120001.1.1725,AB120001.1.1725,244960,Gyrodinium spirale,0,1500
AB120002.1.1725,AB120002.1.1725,244961,Gyrodinium fusiforme,0,1800
AB120003.1.1724,AB120003.1.1724,244962,Gyrodinium rubrum,0,1700
AB120004.1.1723,AB120004.1.1723,244963,Gyrodinium helveticum,0,1500
AB120309.1.1800,AB120309.1.1800,4442,Camellia sinensis,0,1700
Wanted output:
AB179735.1.1711,AB179735.1.1711,278983,Eucyrtidium hexagonatum,0,1600
AB179736.1.1725,AB179736.1.1725,278986,Pterocorys zancleus,0,1763
AB181890.1.1709,AB181890.1.1709,281610,Protoperidinium denticulatum,0,1800
AB120002.1.1725,AB120002.1.1725,244961,Gyrodinium fusiforme,0,1800
AB120309.1.1800,AB120309.1.1800,4442,Camellia sinensis,0,1700
use Text::CSV_XS qw( );
my $csv = Text::CSV_XS->new({
auto_diag => 2,
binary => 1,
quote_space => 0,
});
my %by_genus;
while ( my $row = $csv->getline(\*ARGV) ) {
my ($genus) = split(' ', $row->[3]);
$by_genus{$genus} = $row
if !$by_genus{$genus}
|| $row->[5] > $by_genus{$genus}[5];
}
$csv->say(select(), $_) for values(%by_genus);
Properly naming the variables makes the code more readable:
#! /usr/bin/perl
use warnings;
use strict;
my %selected;
while (<>) {
my ($species, $value) = (split /,/)[3, 5];
my $genus = (split ' ', $species)[0];
if ($value > ($selected{$genus}{max} || 0)) {
$selected{$genus}{max} = $value;
$selected{$genus}{line} = $_;
}
}
for my $genus (keys %selected) {
print $selected{$genus}{line};
}
The order of the output lines is random.
You can this Perl command line as well
perl -F, -lane ' ($g=$F[3])=~s/(^\S+).*/$1/; if( $mx{$g}<$F[-1])
{ $kv{$g}=$_;$mx{$g}=$F[-1] } END { print $kv{$_} for(keys %kv) } ' file
with the given inputs in cara.txt file, the output is
$ perl -F, -lane ' ($g=$F[3])=~s/(^\S+).*/$1/; if( $mx{$g}<$F[-1])
{ $kv{$g}=$_;$mx{$g}=$F[-1] } END { print $kv{$_} for(keys %kv) } ' cara.txt
AB179736.1.1725,AB179736.1.1725,278986,Pterocorys zancleus,0,1763
AB179735.1.1711,AB179735.1.1711,278983,Eucyrtidium hexagonatum,0,1600
AB120309.1.1800,AB120309.1.1800,4442,Camellia sinensis,0,1700
AB120002.1.1725,AB120002.1.1725,244961,Gyrodinium fusiforme,0,1800
AB181890.1.1709,AB181890.1.1709,281610,Protoperidinium denticulatum,0,1800
$
Not fancy but gets the job done
#!/usr/bin/perl
use strict;
my #data = `cat /var/tmp/test.in`;
my %genuses = ();
foreach my $line ( #data ) {
chomp($line);
my #splitline = split(',', $line);
my $genus = $splitline[3];
my $num = $splitline[5];
my ( $name, $extra ) = split(' ', $genus);
if ( exists $genuses{$name}->{'num'} ) {
if ( $genuses{$name}->{'num'} < $num ) {
$genuses{$name}->{'num'} = $num;
$genuses{$name}->{'line'} = $line;
}
else {
next;
}
}
else {
$genuses{$name}->{'num'} = $num;
$genuses{$name}->{'line'} = $line;
}
}
foreach my $genus ( %genuses ) {
print "$genuses{$genus}->{'line'}";
print "\n";
}
Output:
[root#localhost tmp]# ./test.pl
AB179736.1.1725,AB179736.1.1725,278986,Pterocorys zancleus,0,1763
AB179735.1.1711,AB179735.1.1711,278983,Eucyrtidium hexagonatum,0,1600
AB120309.1.1800,AB120309.1.1800,4442,Camellia sinensis,0,1700
AB120002.1.1725,AB120002.1.1725,244961,Gyrodinium fusiforme,0,1800
AB181890.1.1709,AB181890.1.1709,281610,Protoperidinium denticulatum,0,1800
Don't see an obvious method that you are sorting your output by

Using List::Util first on an array of Moose objects

I have an array called aTestCaseList which is initialized and filled with (Moose) objects of type "Testcase". As expected I can print out the Attribute TestName of every Testcase Object in aTestCaseList. But when I try to find the first Object in the list named "Test4" using https://perldoc.perl.org/List/Util.html#first I get the following error
Can't call method "TestName" on an undefined value
Why are the objects in the array suddenly undefined?
use Testcase;
my #aTestcaseList=();
for (my $i=1; $i <= 9; $i++) {
push(#aTestcaseList,Testcase->new("Test".$i));
}
my $sTestcase="Test4";
foreach my $sTestDummy(#aTestcaseList)
{
#Works as expected and prints: Test1 Test2 Test3 ... Test9
print $sTestDummy->TestName." ";
}
# throws the error:
my $sFindTest=first {$_->TestName eq $sTestcase} #aTestcaseList;
package Testcase;
use Moose;
use namespace::autoclean;
has 'TestName' => (is =>'ro',isa=>'Str');
around BUILDARGS => sub
{
my $orig = shift;
my $class = shift;
if ( #_ == 1 && ! ref $_[0] ) {
return $class->$orig(TestName => $_[0]);
}
else {
return $class->$orig(#_);
}
};
__PACKAGE__->meta->make_immutable;
1;
You forgot to import the function first from List::Util like
use List::Util qw(first);

How to check element in a array in PERL with grep?

I would like to check if a element is in the array?
my %hash = (
Value1 => ['10.0.0.1', '10.0.0.2'],
); #/!\NOT ARRAY
my #table = ( '10.0.0.6', '10.0.0.1');
Pseudo-code
my $i = 0;
if( grep { $table[0] eq $_ } eq $hash{"Value1[]"} ) {
print "Find!!!";
$i++; #true
}
if( grep { $table[1] eq $_ } eq $hash{"Value1[]"} ) {
print "Find!!!";
$i++; #true
}
if ( $i = 2) {
print "It is perfect. 0% difference between table and hash{"Value1"}";
}
if ( $i = 1) {
print "It is middle. 50% difference between table and hash{"Value1"}";
}
if ( $i = 0) {
print "It is bad. 100% difference between table and hash{"Value1"}";
}
How to convert hash to array ? Use grep in PERL
I'm not sure for grep syntax "$_"??
I'm only a beginner in PERL.
Thx very much.
for my $ip (#ips_to_find) {
for my $key (keys(%hash)) {
print("$ip in $key\n")
if grep { $_ eq $ip } #{ $hash{$key} };
}
}
You can reduce code by using loop for searching element.
my %hash = ('Value1' => ['10.0.0.1', '10.0.0.2'] );
my #table = ( '10.0.0.6', '10.0.0.1');
my $i = 0;
for my $val (#table) {
if (grep $_ eq $val, #{ $hash{'Value1'} })
{
print "Find!!!\n";
$i++;
}
}
if ( $i == 2) {
print "It is perfect. 0% difference between table and hash{'Value1'}";
}
elsif ( $i == 1) {
print "It is middle. 50% difference between table and hash{'Value1'}";
}
elsif ( $i == 0) {
print "It is bad. 100% difference between table and hash{'Value1'}";
}
Output
G:\Study\Perl Arsenal>perl temp.pl
Find!!!
It is middle. 50% difference between table and hash{'Value1'}
G:\Study\Perl Arsenal>

unable to itherate through the array perl

I have this perl script:
my %perMpPerMercHash;
foreach my $sheet () { #proper ranges specified
foreach my $row ( ) { #proper ranges specified
#required variables declared.
push(#{$perMpPerMercHash{join("-", $mercId, $mpId)}}, $mSku);
}
}
#Finally 'perMpPerMercHash' will be a hash of array`
foreach my $perMpPerMerc ( keys %perMpPerMercHash ) {
&genFile($perMpPerMerc, $perMpPerMercHash{$perMpPerMerc});
}
sub genFile {
my ( $outFileName, #skuArr ) = #_;
my $output = new IO::File(">$outFileName");
my $writer = new XML::Writer( OUTPUT => $output, DATA_MODE => 1, DATA_INDENT => 2);
#mpId is generated.
&prepareMessage($writer, $mpId, #skuArr);
}
sub prepareMessage {
my ( $writer, $mpId, #skuArr ) = #_;
my $count = 1;
print Dumper \#skuArr; #Printing correctly, 8-10 values.
foreach my $sku ( #skuArr ) { #not iterating.
print "loop run" , $sku, "\n"; #printed only once.
}
}
Can somebody please help why this is happening. I am new to perl and could not understand this anomaly.
EDIT:
output of Dumper:
$VAR1 = [
'A',
'B',
'C',
];
When you do
&genFile($perMpPerMerc, $perMpPerMercHash{$perMpPerMerc});
You're passing a reference to an array.
So in
sub genFile {
my ( $outFileName, #skuArr ) = #_;
You have to do :
sub genFile {
my ( $outFileName, $skuArr ) = #_;
and then use #$skuArr.
Have a look at references
The modified genFile sub will be:
sub genFile {
my ( $outFileName, $skuArr ) = #_;
my $output = new IO::File(">$outFileName");
my $writer = new XML::Writer( OUTPUT => $output, DATA_MODE => 1, DATA_INDENT => 2);
#mpId is generated.
&prepareMessage($writer, $mpId, #$skuArr);
}
And the other sub don't need to be modified.
Or you can pass always skuArr by reference:
&genFile($perMpPerMerc, $perMpPerMercHash{$perMpPerMerc});
...
sub genFile {
my ( $outFileName, $skuArr ) = #_;
...
&prepareMessage($writer, $mpId, $skuArr);
}
sub prepareMessage {
my ( $writer, $mpId, $skuArr ) = #_;
my $count = 1;
print Dumper $skuArr;
foreach my $sku ( #$skuArr ) {
print "loop run" , $sku, "\n";
}
}

Resources