The exists() function in Perl is used to check whether an element in an given array or hash exists or not. This function returns 1 if the desired element is present in the given array or hash else returns 0.
JavaScript Array includes() The includes() method returns true if an array contains a specified value. The includes() method returns false if the value is not found.
The Perl grep() function is a filter that runs a regular expression on each element of an array and returns only the elements that evaluate as true. Using regular expressions can be extremely powerful and complex. The grep() functions uses the syntax @List = grep(Expression, @array).
Best general purpose - Especially short arrays (1000 items or less) and coders that are unsure of what optimizations best suit their needs.
# $value can be any regex. be safe
if ( grep( /^$value$/, @array ) ) {
print "found it";
}
It has been mentioned that grep passes through all values even if the first value in the array matches. This is true, however grep is still extremely fast for most cases. If you're talking about short arrays (less than 1000 items) then most algorithms are going to be pretty fast anyway. If you're talking about very long arrays (1,000,000 items) grep is acceptably quick regardless of whether the item is the first or the middle or last in the array.
Optimization Cases for longer arrays:
If your array is sorted, use a "binary search".
If the same array is repeatedly searched many times, copy it into a hash first and then check the hash. If memory is a concern, then move each item from the array into the hash. More memory efficient but destroys the original array.
If same values are searched repeatedly within the array, lazily build a cache. (as each item is searched, first check if the search result was stored in a persisted hash. if the search result is not found in the hash, then search the array and put the result in the persisted hash so that next time we'll find it in the hash and skip the search).
Note: these optimizations will only be faster when dealing with long arrays. Don't over optimize.
Simply turn the array into a hash:
my %params = map { $_ => 1 } @badparams;
if(exists($params{$someparam})) { ... }
You can also add more (unique) params to the list:
$params{$newparam} = 1;
And later get a list of (unique) params back:
@badparams = keys %params;
You can use smartmatch feature in Perl 5.10 as follows:
For literal value lookup doing below will do the trick.
if ( "value" ~~ @array )
For scalar lookup, doing below will work as above.
if ($val ~~ @array)
For inline array doing below, will work as above.
if ( $var ~~ ['bar', 'value', 'foo'] )
In Perl 5.18 smartmatch is flagged as experimental therefore you need to turn off the warnings by turning on experimental pragma by adding below to your script/module:
use experimental 'smartmatch';
Alternatively if you want to avoid the use of smartmatch - then as Aaron said use:
if ( grep( /^$value$/, @array ) ) {
#TODO:
}
This blog post discusses the best answers to this question.
As a short summary, if you can install CPAN modules then the most readable solutions are:
any(@ingredients) eq 'flour';
or
@ingredients->contains('flour');
However, a more common idiom is:
any { $_ eq 'flour' } @ingredients
But please don't use the first()
function! It doesn't express the intent of your code at all. Don't use the ~~
"Smart match" operator: it is broken. And don't use grep()
nor the solution with a hash: they iterate through the whole list.
any()
will stop as soon as it finds your value.
Check out the blog post for more details.
Try to avoid using grep
, if looking at resources.
if ( grep( /^$value$/, @badparams ) ) {
print "found";
}
for (@badparams) {
if ($_ eq $value) {
print "found";
last;
}
}
my %hash = map {$_ => 1} @badparams;
print "found" if (exists $hash{$value});
(added in Perl 5.10, marked is experimental in Perl 5.18).
use experimental 'smartmatch'; # for perl 5.18
print "found" if ($value ~~ @badparams);
List::MoreUtils
use List::MoreUtils qw(any);
@badparams = (1,2,3);
$value = 1;
print "found" if any {$_ == $value} @badparams;
@eakssjo's benchmark is broken - measures creating hashes in loop vs creating regexes in loop. Fixed version (plus I've added List::Util::first
and List::MoreUtils::any
):
use List::Util qw(first);
use List::MoreUtils qw(any);
use Benchmark;
my @list = ( 1..10_000 );
my $hit = 5_000;
my $hit_regex = qr/^$hit$/; # precompute regex
my %params;
$params{$_} = 1 for @list; # precompute hash
timethese(
100_000, {
'any' => sub {
die unless ( any { $hit_regex } @list );
},
'first' => sub {
die unless ( first { $hit_regex } @list );
},
'grep' => sub {
die unless ( grep { $hit_regex } @list );
},
'hash' => sub {
die unless ( $params{$hit} );
},
});
And result (it's for 100_000 iterations, ten times more than in @eakssjo's answer):
Benchmark: timing 100000 iterations of any, first, grep, hash...
any: 0 wallclock secs ( 0.67 usr + 0.00 sys = 0.67 CPU) @ 149253.73/s (n=100000)
first: 1 wallclock secs ( 0.63 usr + 0.01 sys = 0.64 CPU) @ 156250.00/s (n=100000)
grep: 42 wallclock secs (41.95 usr + 0.08 sys = 42.03 CPU) @ 2379.25/s (n=100000)
hash: 0 wallclock secs ( 0.01 usr + 0.00 sys = 0.01 CPU) @ 10000000.00/s (n=100000)
(warning: too few iterations for a reliable count)
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