I've an array like this:
my @arr = (5, 76, 1000, 21, 47);
And this hash:
my %hash = (
Meta => [1000],
);
If any of the values of the hash matches any of the elements of the array, I want to print the key value of that match. For doing this, I'm using the following function, and it works:
my ($match) = grep { "@{$hash{$_}}" ~~ @arr } keys %hash;
The problem comes when I have more than one element in the hash of arrays, for example:
my %hash = (
Meta => [1000, 2],
);
In this case, I also want to return the key ("Meta") since the value 1000 is in the array, but I don't get it.
You can use intersect
from Array::Utils to do that.
use strict;
use warnings;
use Array::Utils 'intersect';
my @arr = (5, 76, 1000, 21, 47);
my %hash = (
Meta => [1000, 2],
Foo => [1, 2, 3],
Bar => [47],
);
my @match = grep { intersect(@{$hash{$_}}, @arr) } keys %hash;
p @match;
This prints:
[
[0] "Bar",
[1] "Meta"
]
Note I changed $match
to @match
to accomodate more than one key, so I can show match and non-match examples.
The following will be faster than Array::Utils's intersect
because it only builds %set1
once (instead of once per element of %groups
):
my @set1 = (5, 76, 1000, 21, 47);
my %set1 = map { $_ => 1 } @set1;
my %groups = (
Meta => [1000, 2],
Foo => [1, 2, 3],
Bar => [47],
);
my @matches = grep {
my $set2 = $groups{$_};
grep { $set1{$_} } @$set2
} keys %groups;
For large groups, you might want to use a short-circuiting loop instead of the inner grep
, but grep
should be faster for small groups.
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