I have a function to search an array of objects for a matching value using the eq operator, like so:
sub find {
my ( $self, %params ) = @_;
my @entries = @{ $self->{_entries} };
if ( $params{filename} ) {
@e开发者_开发问答ntries = grep { $_->filename eq $params{filename} } @entries;
}
if ( $params{date} ) {
@entries = grep { $_->date eq $params{date} } @entries;
}
if ( $params{title} ) {
@entries = grep { $_->title eq $params{title} } @entries;
}
....
I wanted to also be able to pass in a qr quoted variable to use in the comparison instead but the only way I can think of separating the comparisons is using an if/else block, like so:
if (lc ref($params{whatever}) eq 'regexp') {
#use =~
} else {
#use eq
}
Is there a shorter way of doing it? Because of reasons beyond my control I'm using Perl 5.8.8 so I can't use the smart match operator.
TIA
This is Perl, so of course there's a CPAN module: Match::Smart. It works very similarly to Perl 5.10's smart match operator, only you type smart_match($a, $b)
rather than $a ~~ $b
.
You may wish to compare with the perlsyn documentation for 5.10 smartmatching as Match::Smart handles quite a few more situations.
Otherwise, I don't see anything wrong with:
sub smart_match {
my ($target, $param) = @_;
if (ref $param eq 'Regexp') {
return ($target =~ qr/$param/);
}
else {
return ($target eq $param);
}
}
@entries = grep { smart_match($_->date, $params{date}) } @entries;
I don't know exactly what you want your end result to be, but you can do:
for my $field (qw(filename date title)) {
my $p = $param($field};
@entries = (ref($p) eq 'regexp')
? grep { $_->$field =~ /$p/ } @entries
: grep { $_->$field eq $p } @entries;
}
Alternatively, you can turn even your 'eq' comparisions into regular expressions, e.g.:
my $entry = "string to be equal to";
my $re = qr/^\Q$entry\E/;
and that simplifies the logic in the for loop.
精彩评论