Issue while comparing hashes of array in perl - perl

I am pretty new to Perl and need to accomplish a task quickly. Any help is appreciated!
I have two hash of arrays as follows:
Hash 1
-------
abc.txt: ['0744','0']
xyz.txt: ['0744','0']
Hash 2
-------
abc.txt: ['0766','0']
x.txt: ['0744','0']
I have to compare these 2 hashes print 3 things:
1. Files Added in Hash2
2. Files Missing in Hash2
3. Files(keys) which are present in both hashes but there attributes(values) are different.
print "-------------------------ADDED FILES--------------------------------";
foreach (keys %hash2){
print "added $_\n" unless exists $hash1{$_};
}
print "-------------------------MISSING FILES--------------------------------";
foreach (keys %hash1){
print "Missing $_\n" unless exists $hash2{$_};
}
print "-------------------------Different permissions--------------------------------";
foreach my $key2 ( keys %hash2 ) {
unless ( exists $hash1{$key2} ) { next; };
if (join(",", sort #{ $hash1{$_}})
eq join(",", sort #{ $hash2{$_}}) ){
}
else{
print "value is different";
}
}
Issue is when keys are same.This for each loop doesn't work well.I want to print like this:
FileName: File Attributes Before : File Attributes after
abc.txt: '0744','0': 0766','0'
Please help

Your code didn't work, because you defined my $key2 in your foreach-loop, which leaves $_ as an empty value.
Also you don't need to join the hashes. Try the smartmatch operator on array values, its more efficient since you only need to do the join, when you want to have an output.
foreach my $key2 ( keys %hash2 ) {
unless ( exists $hash1{$key2} ) { next; };
unless ( $hash1{$key2} ~~ $hash2{ $key2 } )
{
print "$key2: ".join(",", #{ $hash1{$key2}}).": ".join(",", #{ $hash2{$key2}})."\n"
}
}

Change
foreach my $key2 ( keys %hash2 ) {
unless ( exists $hash1{$key2} ) { next; };
if (join(",", sort #{ $hash1{$_}})
eq join(",", sort #{ $hash2{$_}}) ){
}
else{
print "value is different";
}
}
to
foreach my $key2 ( keys %hash2 ) {
next unless ( exists $hash1{$key2} );
my $val1 = join(",", sort #{ $hash1{$key2} });
my $val2 = join(",", sort #{ $hash2{$key2} });
if ($val1 eq $val2) {
# values are same
}
else {
print "$key2 $val1 $val2\n";
}
}
and try again.

Related

perl variable not storing data outside block

I have written below mention code to read a file and and storing data to array #s_arr.
But when I am trying to print that #s_arr array outside the block it shows nothing.
use Data::Dumper;
my #s_arr;
my #err;
my %sort_h_1;
$fname = '/qv/Error.log';
open( IN, "<$fname" );
foreach $line ( <IN> ) {
if ( $line =~ /CODE\+(\w{3})(\d{5})/ ) {
$a = "$1$2";
push #err, $a;
}
}
close IN;
$prev = "";
$count = 0;
my %hash;
foreach ( sort #err ) {
if ( $prev ne $_ ) {
if ( $count ) {
$hash{$prev} = $count;
}
$prev = $_;
$count = 0;
}
$count++;
}
print Dumper \%hash;
printf( "%s:%d\n", $prev, $count ) if $count;
$hash{$prev} = $count;
my $c = 0;
print "Today Error Count\n";
foreach my $name ( sort { $hash{$b} <=> $hash{$a} } keys %hash ) {
#printf "%-8s %s\n", $name, $hash{$name};
#my %sort_h ;
push #s_arr, $name;
push #s_arr, $hash{$name};
#$sort_h{$name} = $hash{$name} ;
#print Dumper \%sort_h ;
#print Dumper \#s_arr ;
$c++;
if ( $c eq 30 ) {
exit;
}
}
print Dumper \#s_arr; # It's showing nothing
You are calling exit inside of your foreach loop. That makes the program stop, and the print Dumper #s_arr is never reached.
To break out of a loop you need to use last.
foreach my $name ( sort ... ) {
# ...
$c++;
last if $c == 30; # break out of the loop when $c reaches 30
}
I used the postfix variant of if here because that makes it way easier to read. Also note that as zdim pointed out above, you should use the numerical equality check == when checking for numbers. eq is for strings.

Double hash entries while printing

As part of a bigger program I've got a hash. I'm testing the program printing the keys but they are all duplicates, I don't know why
while ( my $line = <SEQ> ) {
chomp $line;
$line =~ s/>//;
my ( #split1 ) = split( "\t", $line );
foreach my $chr ( keys %position ) {
#print Dumper \%position;
print "$chr\n";
foreach my $pos ( sort keys %{ $position{$chr} } ) {
if ( $split1[0] =~ /$chr/ ) {
#print "$chr\t$pos\n";
}
}
}
}
%position is a nested hash, when I print the keys on print "$chr\n"; they are all doubled and I don't understand why.
The file opened on handle SEQ looks like this:
>chr1\tACTGTAGTCTCATCCTAT...
>chr2\tACGTAGCTAGT....
and so on
You have a foreach loop inside a while which will print all of the keys of the %position hash for every line of input
That will cause symptoms like what you're describing. Is that what you're looking for?
Start with this:
my %data;
while(<DATA>){
chomp;
my ($chr, $seq) = split;
$data{$chr} = $seq;
}
print Dumper \%data;

How to concatenate values for duplicate hash keys in Perl?

I know it is not possible to have duplicate keys in a hash, but this is what my data looks like:
Key Value
SETUP_FACE_PROT great
SETUP_FACE_PROT great2
SETUP_FACE_PROT great3
SETUP_FACE_PROT great3
SETUP_ARM_PROT arm
SETUP_FOOT_PROT foot
SETUP_FOOT_PROT foot2
SETUP_HEAD_PROT goggle
I would like to concatenate values for repeated keys, separated by a * character. For example, this is what I want the output to look like:
SETUP_FACE_PROT'=great*great2*great3',
SETUP_ARM_PROT='arm',
SETUP_FOOT_PROT='foot*foot2',
SETUP_HEAD_PROT='google'
This is how I've tried to solve the problem so far:
foreach my $key ( sort keys %stuff )
{
print "$key=\'", join( "*", #{ $stuff{$key} } ), "\'\n";
}
But instead of printing the result, how can I store it in a variable so that I can pass it to another subroutine? I'm trying to create a new string that looks like this:
$newstring="
SETUP_FACE_PROT='great*great2*great3',
SETUP_ARM_PROT='arm',
SETUP_FOOT_PROT='foot*foot2',
SETUP_HEAD_PROT='google' "
You can't duplicate keys, you can create a hash of arrays.
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
my %stuff;
while (<DATA>) {
my ( $key, $value ) = split;
push( #{ $stuff{$key} }, $value );
}
print Dumper \%stuff;
foreach my $key ( sort keys %stuff ) {
print "$key=\'", join( "*", #{ $stuff{$key} } ), "\'\n";
}
__DATA__
SETUP_FACE_PROT great
SETUP_FACE_PROT great2
SETUP_FACE_PROT great3
SETUP_FACE_PROT great3
SETUP_ARM_PROT arm
SETUP_FOOT_PROT foot
SETUP_FOOT_PROT foot2
SETUP_HEAD_PROT goggle
Edit:
Turning it into a string as requested:
my $results;
foreach my $key ( sort keys %stuff ) {
$results .= "$key=\'". join( "*", #{ $stuff{$key} } ). "\'\n";
}
print $results;
Or perhaps using print still with a filehandle:
my $results;
open ( my $output, '>', \$results );
foreach my $key ( sort keys %stuff ) {
print {$output} "$key=\'", join( "*", #{ $stuff{$key} } ), "\'\n";
}
close ( $output );
print $results;
At last i got an answer doing this.
use Data::Dumper;
my %stuff;
use Text::CSV;
my $csv = Text::CSV_XS->new ({ binary => 1, eol => $/ });
my $filenamex = 'duplicate2.csv';
$checkstring ='';
open(my $datab, '<', $filenamex) or die "Could not open '$filename' $!\n";
$i=1;
my %datan;
while (my $linea = <$datab>)
{
chomp $linea;
#fieldsx = split ",",$linea;
$key = $fieldsx[0];
$value = $fieldsx[1];
# print $key;
push( #{ $stuff{$key} }, $value );
}
foreach my $key ( sort keys %stuff )
{
$checkstring = $checkstring.','.$key.'='. join( "*", #{ $stuff{$key} } );
}
print $checkstring;

Printing out associated key with values in Perl in foreach loop

I am trying to print out the key for the hash if the value satisfies a certain condition. However, I am not sure how to access the hash key if it satisfies the value condition. This is the code I have:
foreach my $x (values %hash){
if ($x > $ARGV[1]){
$counter = $counter + 1
print "keys %hash\n"
}
}
print "$counter\n"
When you loop over the values, you have no access to the key.
for my $key (keys %hash) {
if ($hash{$key} > $ARGV[1]) {
$counter = $counter + 1;
print "$key\n";
}
}
print "$counter\n";
or
keys %hash; # reset iterator
while (my ($key, $value) = each %hash) {
if ($value > $ARGV[1]) {
$counter = $counter + 1;
print "$key\n";
}
}
print "$counter\n";
You can't access the key of a hash element given its value. After all, multiple keys may have the same value. But you can rely on Perl giving you the keys in the same order as the values. So you could write something like this
use strict;
use warnings;
my #keys = keys %hash;
my #vals = values %hash;
my $count = 0;
for my $val ( #values ) {
my $key = shift #keys;
if ( $val > $ARGV[1] ) {
++$count;
print $key, "\n";
}
}
print "$count\n";
But it would be far better to use a while loop with each to gather both the key and the value at the same time
while ( my ($key, $val) = each %hash ) {
if ( $val > $ARGV[1] ) {
++$count;
print $key, "\n";
}
}

get hash ref key and value from another script

Hi all
I have a module with a sub that get its parameters from e.g. script.pl
In script.pl I call the function this way moduleName::sunName(\%hashref).
Now in module, and in sub body I want to print those parameters that passed. also I want to check if the value of each key of this href is empty print '-' instead of 0.
first part of module:
sub printOptions {
my $opt = shift;
# I have this
print $opt->{'id'};
# But I need all parameters!
}
thanks
Try:
sub printOptions {
my $opt = shift #_;
for my $key ( sort keys %$opt ){
if( defined( $opt->{$key} )){
print "$key: $opt->{$key}\n";
}else{
print "$key: undef\n";
}
}
}
Matt, what are you getting at the moment? To dereference the reference $opt you can do
%opt = %{ $opt }
To iterate over the keys you can then do
for my $key ( sort keys %opt ) {
print "$key: " . ($opt{ $key } || '-') . "\n";
}