Re: Comparing against multiple values
by PrimeLord (Pilgrim) on Mar 18, 2002 at 19:19 UTC
|
I am not sure if it would be faster or not, but you could always store each of the match terms as keys in a hash and do something like this.
my %hash = qw(
$bar => 1
$baz => 1
$boo => 1
);
print "yep!\n" if exists $hash{$foo};
HTH
-Prime
Update: I tested the code and it is considerably faster. The first benchmark time is the regex solution and the second benchmark time is using a hash. Both tests were run 100,000 times.
Regex Solution
timethis 100000: 18 wallclock secs ( 0.41 usr + 0.05 sys = 0.45 CPU)
Hash Solution
timethis 100000: 1 wallclock secs ( 1.58 usr + 0.00 sys = 1.58 CPU)
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Maybe you want to score points for obfuscation:
if ({map{$_=>1}($bar,$baz,$boo)}->{$foo})
{
print "Yes!\n";
}
A dirty, and almost as quick way is:
if (grep{$_ eq $foo} $bar, $baz, $boo)
# ...
If you are comparing frequently, you might want to have a persistent hash which you can refer to on a regular basis. Why create it every time if it is the same?
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Comparing against multiple values
by larsen (Parson) on Mar 18, 2002 at 19:29 UTC
|
use Quantum::Superpositions;
use strict;
if ($foo eq any( $bar, $baz, $boo )) {
print "Yep!";
}
| [reply] [Watch: Dir/Any] [d/l] |
Re: Comparing against multiple values (boo)
by boo_radley (Parson) on Mar 18, 2002 at 19:36 UTC
|
While that's very easy, it's not as fast as using a comparison operator such as 'eq' or '=='. However using these often leads to redundant and cumbersome looking code:
have you met my friend, grep?
my @values= qw(foo bar baz bax);
my $test = "foo";
print "woo\n" if (grep {$_ eq $test}@values) ;
This is probably not the hottest use for grep if you've got a long list of values, since it'll build an array of values matching the test only to use the result in a scalar fashion. It'd be handy if you could last in a grep in this particular instance.
You could produce the same behavior in a for loop quite easily that would exit on the first found value.
| [reply] [Watch: Dir/Any] [d/l] |
Re: Comparing against multiple values
by buckaduck (Chaplain) on Mar 18, 2002 at 19:45 UTC
|
Could be a candidate for the Switch module:
use Switch;
switch ($foo) {
case [$bar,$baz,$boo] { print "yep!\n" }
}
buckaduck | [reply] [Watch: Dir/Any] [d/l] |
Re: Comparing against multiple values
by dws (Chancellor) on Mar 18, 2002 at 19:34 UTC
|
While that's very easy, it's not as fast as using a comparison operator such as 'eq'
If you're truly concerned about speed, use a /o modifier to compile the regex once, rather than re-interpolating the variable each time the regex is fired.
You'll also need to fix the regex to avoid false positives. Here's how I do it:
my $re = "\A(?:"
. join("|", $foo, $bar, $baz)
. ")\Z";
...
if ( /$re/o ) { ... }
| [reply] [Watch: Dir/Any] [d/l] |
Re: Comparing against multiple values
by AidanLee (Chaplain) on Mar 18, 2002 at 23:07 UTC
|
PrimeLord's hash suggestion is quite good. I'd suggest also maybe a for loop as something more traditional:
for( qw( foo bar baz ) ){
print "yep" and last if $test eq $_;
}
or all on one line:
print "yep" and last if $test eq $_ for( qw( foo bar baz ) );
if it'll be a more complex action down the line, you can "do":
do { print "yep"; last; } if $test eq $_ for( qw( foo bar baz ) );
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Comparing against multiple values
by shotgunefx (Parson) on Mar 18, 2002 at 20:02 UTC
|
If the result is to call some sub then I would just use a hash but sometimes I use a little snippet like so.
#!/usr/bin/perl
sub matches(&;@) {
my $coderef = shift ;
my @data = @_;
for (my $i=0; $i <= $#data; $i++ ){
$_ = $data[$i];
if (&$coderef){
return wantarray ? ($_ ,($i ) ) : $_;
}
}
return;
}
my @actions = qw(get fetch store info print);
if (my ($v,$i) = matches { $action eq $_ } @actions ){
print "Found $v at $i\n";
}
# Or
if (my $v = matches { $action eq $_ } @actions ){
print "Found $v $i\n";
}
# Or
die "Damn! Invalid action $action" unless matches{$action eq $_ } @act
+ions;
-Lee
"To be civilized is to deny one's nature." | [reply] [Watch: Dir/Any] [d/l] |
Re: Comparing against multiple values
by flocto (Pilgrim) on Mar 18, 2002 at 21:38 UTC
|
There are a few solutions that came to my mind:
my $code = "sub check { my \$val = shift; if (";
$code .= join (' or ', map { "\$val eq \"$_\""; } (@ceck_vals));
$code .= ") { return 1; } else { return 0; } }";
eval $code;
Propably quite performent if you have to check for these values very often and they never change (CGIs, for example..)
---
my %check = map { $_ => 1; } (@ceck_vals);
if ($check{$val}) { do_foo (); }
Propably the better choice if @check_vals often changes..
---
if (grep { $val eq $_ } (@check_vals)) { do_foo (); }
I expect it to be kind of slow..
---
my $regex = join ('|', @check_vals);
if ($val =~ m/$re/) { do_foo (); }
This is slow, but it can match parts of $val, in case this is needed..
---
There are more, but these were the ones I like the most :) Have fun ;)
Regards,
octo
P.S.: I didn't do ANY performance tests, so my guesses are likely to be wrong, please don't rely on this! | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Comparing against multiple values
by traveler (Parson) on Mar 18, 2002 at 22:04 UTC
|
You could also use Meta::Ds::Hash. Something like this (untested):
use Meta::Ds::Hash;
my($hash)=Meta::Ds::Hash->new();
$hash->insert($bar);
$hash->insert($baz);
$hash->insert($boo);
# later
if($hash->has($foo)) {
print "Found it\n";
}
It would be interesting to compare these various solutions for large and small numbers of comparison sets.
HTH, --traveler | [reply] [Watch: Dir/Any] [d/l] [select] |
|
i don't know how to reply to the whole thread
so i have used the last answer, sorry for that.
if ($foo=~/$bar|$baz|$boo/){
is not strictly equivalent to
if (($foo eq $bar) || ($foo eq $baz) || ($foo eq $boo)){
as =~ will be true for $foo=abc and $boo=ab
but "abc" will not be eq to "ab"
if you want them to be strictly equivalent then it will be something like :
if ($foo=~/^$bar$|^$baz$|^$boo$/){
i have tested with string values but not with $var
so maybe there is some \ to use at the good places for this to work
regards.
| [reply] [Watch: Dir/Any] |