Reputation: 972
I have two arrays and a hash holds these arrays
Array 1:
my $group = "west"
@{ $my_big_hash{$group} } = (1534,2341,2322,3345,689,3333,4444,5533,3334,5666,6676,3435);
Array 2 :
my $element = "Location" ;
my $group = "west" ;
@{ $my_tiny_hash{$element}{$group} } = (153,333,667,343);
Now i would want to compare
@{ $my_tiny_hash{$element}{$group} }
with
@{ $my_big_hash{$group} }
and check whether all the elements of tiny hash array are a part of big_hash array . As we can see tiny hash has just 3 digit elements and all these elements are matching with big hash if we just compare the first 3 digits
if first 3 digits/letters match and all are available in the big array, then its matching or We have to print the unmatched elements
Its an array to array comparison. How do we achieve it.
PS : Without Array Utils , How to achieve it
The solution using Array Utils is really simple
my @minus = array_minus( @{ $my_tiny_hash{$element}{$group} } , @{ $my_big_hash{$group} } );
But it compares all the digits and i would just want to match the first 3 digits
Hope this is clear
Thanks
Upvotes: 2
Views: 382
Reputation: 525
An alternative, using ordered comparison instead of hashes:
@big = sort (1534,2341,2322,3345,689,3333,4444,5533,3334,5666,6676,3435);
@tiny = sort (153,333,667,343,698);
for(@tiny){
shift @big while @big and ($big[0] cmp $_) <0;
push @{$result{
$_ eq substr($big[0],0,3)
? "found" : "missing" }},
$_;
}
Contents of %result
:
{
'found' => [
153,
333,
343,
667
],
'missing' => [
698
]
}
Upvotes: 1
Reputation: 69274
This seems to do what you want.
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
my (%big_hash, %tiny_hash);
my $group = 'west';
my $element = 'Location';
# Less confusing initialisation!
$big_hash{$group} = [1534,2341,2322,3345,689,3333,4444,5533,3334,5666,6676,3435];
$tiny_hash{$element}{$group} = [153,333,667,343];
# Create a hash where the keys are the first three digits of the numbers
# in the big array. Doesn't matter what the values are.
my %check_hash = map { substr($_, 0, 3) => 1 } @{ $big_hash{$group} };
# grep the small array by checking the elements' existence in %check_hash
my @missing = grep { ! exists $check_hash{$_} } @{ $tiny_hash{$element}{$group} };
say "Missing items: @missing";
Update: Another solution that seems closer to your original code.
my @truncated_big_array = map { substr($_, 0, 3) } @{ $big_hash{$group} };
my @minus = array_minus( @{ $my_tiny_hash{$element}{$group} } , @truncated_big_array );
Upvotes: 7
Reputation: 21676
A quick and bit dirty solution (which extends your existing code).
#!/usr/bin/perl
use strict;
use warnings;
my (%my_big_hash, %my_tiny_hash, @temp_array);
my $group = "west";
@{ $my_big_hash{$group} } = (1534,343,2341,2322,3345,689,3333,4444,5533,3334,5666,6676,3435);
foreach (@{ $my_big_hash{$group} }){
push @temp_array, substr $_, 0,3;
}
my $element = "Location";
my $group2 = "west";
@{ $my_tiny_hash{$element}{$group2} } = (153,333,667,343,698);
#solution below
my %hash = map { $_ => 1 } @temp_array;
foreach my $search (@{$my_tiny_hash{'Location'}->{west}}){
if (exists $hash{$search}){
print "$search exists\n";
}
else{
print "$search does not exist\n";
}
}
Output:
153 exists
333 exists
667 exists
343 exists
698 does not exist
Also see: https://stackoverflow.com/a/39585810/257635
Edit: As per request using Array::Utils.
foreach (@{ $my_big_hash{$group} }){
push @temp_array, substr $_, 0,3;
}
my @minus = array_minus( @{ $my_tiny_hash{$element}{$group} } , @temp_array );
print "@minus";
Upvotes: 2