I tried to put key-value pairs at %hash1 if key exists in %hash There is one element in array for which there is no entry at %hash ex: @array = (1,2,3,4,5); #there is no hash entry for key 1 at %hash
So I thought map would do the job and I will get 4 keys in my new hash i.e. %hash1 but it gives 5 keys. At the same time I tried foreach and it worked. I was in delusion that we can replace foreach using map, but this case made me to think. Can anyone explain, where my logic goes wrong?
#Method 1. Comment it while using Method 2
%hash1 = map { $_=>$hash{$_} if(exists $hash{$_}) } @array;
# Method 2. Comment whole loop while using method 1
foreach (@array){
$hash1{$_} = $hash{$_} if(exists $hash{$_});
}
Your problem is that your map expression returns a false value for the first element in undef@array. And that gets stringified to an empty string as it's being used as a hash key. (In the comments Borodin points out that this explanation is incorrect. In fact the empty string comes from the false value that is returned from exists when the key is "1")
You might get a better idea of what is doing on if you a) turn on strict and warnings and b) use Data::Dumper to display the hash once you've created it.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper;
my @array = (1 .. 5);
my %hash = ( 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five' );
my %hash1 = map { $_=>$hash{$_} if(exists $hash{$_}) } @array;
say Dumper \%hash1;
That shows that you end up with a hash like this:
$ ./hash
Odd number of elements in hash assignment at ./hash line 12.
$VAR1 = {
'' => 2,
'three' => 4,
'five' => undef,
'two' => 3,
'four' => 5
};
You are generating a list with an odd number of elements. And that doesn't make a happy hash.
When you're building a hash you need to ensure that you have an even number of elements. So when you're using map you need to return either zero or two elements for each iteration. So you need something like this:
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper;
my @array = (1 .. 5);
my %hash = ( 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five' );
my %hash1 = map { exists $hash{$_} ? ($_ => $hash{$_}) : () } @array;
say Dumper \%hash1;
Note that we explicitly return an empty list when a key isn't found in the first hash.
$ ./hash2
$VAR1 = {
'4' => 'four',
'3' => 'three',
'2' => 'two',
'5' => 'five'
};
map will always return what you put in its code block. So the return value for
%hash1 = map { $_=>$hash{$_} if(exists $hash{$_}) } @array;
will be $_=>$hash{$_} when $hash{$_} exists and "" if it doesn't exist.
What you probably wanted to write:
my %hash1 = map { exists($hash{$_}) ? ($_ => $hash{$_}) : () }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With