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

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>

Related

Unable to find if one item exists in array of items and return the necessary message in Perl

I have array of IDs. I have one ID which I want to find if that ID exists in the array of IDs in Perl
I tried the following code:
my $ids = [7,8,9];
my $id = 9;
foreach my $new_id (#$ids) {
if ($new_id == $id) {
print 'yes';
} else {
print 'no';
}
}
I get the output as:
nonoyes
Instead I want to get the output as only:
yes
Since ID exists in array of IDs
Can anyone please help ?
Thanks in advance
my $ids = [7,8,9];
my $id = 9;
if (grep $_ == $id, #ids) {
print $id. " is in the array of ids";
} else {
print $id. " is NOT in the array";
}
You just need to remove the else part and break the loop on finding the match:
my $flag = 0;
foreach my $new_id (#$ids) {
if ($new_id == $id) {
print 'yes';
$flag = 1;
last;
}
}
if ($flag == 0){
print "no";
}
Another option using hash:
my %hash = map { $_ => 1 } #$ids;
if (exists($hash{$id})){
print "yes";
}else{
print "no";
}
use List::Util qw(any); # core module
my $id = 9;
my $ids = [7,8,9];
my $found_it = any { $_ == $id } #$ids;
print "yes" if $found_it;
The following piece of code should cover your requirements
use strict;
use warnings;
my $ids = [7,8,9];
my $id = 9;
my $flag = 0;
map{ $flag = 1 if $_ == $id } #$ids;
print $flag ? 'yes' : 'no';
NOTE: perhaps my #ids = [7,8,9]; is better way to assign an array to variable

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

Perl deleting array elements after a few iterations of code, with a call to a sub function

My code works for the first few iterations, but after a few times through the while loop, it seems that my array elements are being deleted.
I'm taking numbers off the array constructed from the input parameters and all I can tell is that when I get to a number which was passed in twice, I get an error.
I am calling my script like this
./branchandboundNoComments.pl 1 2 3 4 5 5 7 7 9 9 10 10 12 14 19
I should get this as output
0, 7, 9, 10, 14, 19
This is my script
#!/usr/bin/perl -w
use strict;
my #input = #ARGV;
my $maxAll = $input[-1];
$#input = $#input - 1;
my #multiset = ( 0, $maxAll );
my #stack;
my $rotation = 0; # this is 0,1, or 2.
while ( #input != 0 ) {
my $max = $input[-1];
my #deltamultiset;
for ( my $i = 1; $i <= $#multiset; $i++ ) {
push #deltamultiset, $multiset[$i] - $max;
}
push #deltamultiset, $max;
my #deltamultiset2;
for ( my $i = 1; $i <= $#multiset; $i++ ) {
push #deltamultiset2, $multiset[$i] - ( $maxAll - $max );
}
push #deltamultiset2, $max;
if ( subset( \#deltamultiset, \#input ) and $rotation == 0 ) {
for ( my $i = 0; $i < $#deltamultiset; $i++ ) {
pop #input;
}
push #multiset, $max;
push #stack, $max;
push #stack, 0;
}
elsif ( subset( \#deltamultiset2, \#input ) and $rotation <= 1 ) {
for ( my $j = 0; $j < $#deltamultiset; $j++ ) {
pop #input;
}
push #multiset, ( $maxAll - $max );
push #stack, ( $maxAll - $max );
push #stack, 1;
$rotation = 0;
}
elsif ( #stack != 0 ) {
$rotation = $stack[-1];
$#stack--;
$max = $stack[-1];
$#stack--;
$rotation++;
for ( my $i = 0; $i < $#multiset; $i++ ) {
if ( $multiset[$i] == $max ) {
delete $multiset[$i];
last;
}
}
for ( my $i = 0; $i < $#deltamultiset; $i++ ) {
push #input, $deltamultiset[$i];
}
}
else {
print "no solutions \n";
exit;
}
}
print "#multiset is a solution \n";
sub subset {
my ( $deltamultisetSubref, $multisetSubref ) = #_;
my #deltamultisetSub = #{$deltamultisetSubref};
my #multisetSub = #{$multisetSubref};
while ( #deltamultisetSub != 0 ) {
for ( my $i = $#multisetSub; $i >= -1; $i-- ) {
if ( $multisetSub[$i] == $deltamultisetSub[-1] ) {
pop #deltamultisetSub;
$#multisetSub--;
last;
}
if ( $i == -1 ) {
return 0;
}
}
}
return 1;
}
This is what is output
Use of uninitialized value in subtraction (-) at ./branchandboundNoComments.pl line 20.
Use of uninitialized value in subtraction (-) at ./branchandboundNoComments.pl line 26.
no solutions
I can't understand the algorithm you're trying to implement, so there are probably more errors, but the immediate problem is that the statement
delete $multiset[$i]
won't remove that element from the array unless it is the last element; otherwise the array stays the same length, exists on that element will return false, and it will evaluate to undef
If you want to remove the element, which seems most likely, then you want
splice #multiset, $i, 1;
But I have tested your code with that fix in place, and while it no longer produces Use of uninitialized value in subtraction errors, the result is still
no solutions
Unfortunately I can't understand what you're trying to implement, and can't make any useful guesses about what may be wrong unless you can offer me a description of the underlying algorithm

creating hash of hashes in perl

I have an array with contain values like
my #tmp = ('db::createParamDef xy', 'data $data1', 'model $model1', 'db::createParamDef wl', 'data $data2', 'model $model2')
I want to create a hash of hashes with values of xy and wl
my %hash;
my #val;
for my $file(#files){
for my $mod(#tmp){
if($mod=~ /db::createParamDef\s(\w+)/){
$hash{$file}="$1";
}
else{
my $value = split(/^\w+\s+/, $mod);
push (#val,$values);
}
$hash{$fname}{$1}="#val";
#val=();
}
}
this returns me only the filename and the value of $1, but i'm expecting output to be like this:
%hash=(
'filename1'=>
{
'xy'=>'$data1,$model1',
}
'filename2'=>
{
'wl'=>'$data2,$model2',
}
)
where am I doing wrong?!
This was actually a pretty tricky problem. Try something like this:
#!/bin/perl
use strict;
use warnings;
my #tmp = ('db::createParamDef xy', 'data $data1', 'model $model1', 'db::createParamDef wl', 'data $data2', 'model $model2');
my #files = ('filename1', 'filename2');
my %hash;
my #val;
my $index = 0;
my $current;
for my $mod (#tmp) {
if ( $mod=~ /db::createParamDef\s+(\w+)/){
$current = $1;
$hash{$files[$index]}={$current => ""};
$index++;
#val=();
} else {
my $value = (split(/\s+/, $mod))[1];
push (#val,$value);
}
$hash{$files[$index - 1]}{$current} = join(",", #val);
}
use Data::Dumper;
print Dumper \%hash;
Let me know if you have any questions about how it works!
my #tmp = (
'db::createParamDef xy', 'data $data1', 'model $model1',
'db::createParamDef wl', 'data $data2', 'model $model2'
);
my $count = 0;
my %hash = map {
my %r;
if (my($m) = $tmp[$_] =~ /db::createParamDef\s(\w+)/) {
my $i = $_;
my #vals = map { $tmp[$i+$_] =~ /(\S+)$/ } 1..2;
$r{"filename". ++$count}{$m} = join ",", #vals;
}
%r;
} 0 .. $#tmp;
use Data::Dumper; print Dumper \%hash;
output
$VAR1 = {
'filename1' => {
'xy' => '$data1,$model1'
},
'filename2' => {
'wl' => '$data2,$model2'
}
};

Warning message in older perl version

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) ).

Resources