use 5.010;
my $x = 40;
given ($x)
{
when ([0..9, 50..59]) { say 0 }
when ([10..19, 60..69]) { say 1 }
when ([20..29, 70..79]) { say 2 }
when ([30..39, 80..89]) { say 3 }
when ([40..49, 90..99]) { say 4 }
}
As of Perl 5.14 (which is incidentally the oldest officially supported version of Perl, so if you've not upgraded yet, why not?), you can also use when as a statement modifier...
use 5.014;
my $x = 40;
given ($x)
{
say 0 when [0..9, 50..59];
say 1 when [10..19, 60..69];
say 2 when [20..29, 70..79];
say 3 when [30..39, 80..89];
say 4 when [40..49, 90..99];
}
Or smart match with no topicalising...
use 5.010;
my $x = 40;
say 0 if $x ~~ [0..9, 50..59];
say 1 if $x ~~ [10..19, 60..69];
say 2 if $x ~~ [20..29, 70..79];
say 3 if $x ~~ [30..39, 80..89];
say 4 if $x ~~ [40..49, 90..99];
And here's another technique using Smart::Dispatch...
use Smart::Dispatch;
my $x = 40;
my $tiers = dispatcher {
match [0..9, 50..59], dispatch { 0 };
match [10..19, 60..69], dispatch { 1 };
match [20..29, 70..79], dispatch { 2 };
match [30..39, 80..89], dispatch { 3 };
match [40..49, 90..99], dispatch { 4 };
};
say $tiers->($x);
And a last one using a regular hash, which has the advantage that it should work with even really ancient Perl 5.x releases.
my $x = 40;
my %tiers = (
(map { $_ => 0 } 0..9, 50..59),
(map { $_ => 1 } 10..19, 60..69),
(map { $_ => 2 } 20..29, 70..79),
(map { $_ => 3 } 30..39, 80..89),
(map { $_ => 4 } 40..49, 90..99),
);
print $tiers{$x} . "\n";
What are the advantages of each solution? Well, a hash is nice in that it can be stored in a variable and passed around easily; it can be inspected, modified, etc. However, it can only deal with finite sets of keys. If you need to be able to match, say, all floating point numbers between 2.1 and 2.3, then you don't want to list them all in a hash!
The aim of Smart::Dispatch is to retain the benefits of hash-based dispatch tables (the ability to pass a reference to them around; inspect them; modify them) but without needing to enumerate all the hash keys.
The others, using Perl's built-in decision syntax (i.e. if, given, when, etc) will likely run a little faster (though may compile a little slower than a hash), but passing around references to them is more awkward (you'd need to write a wrapper sub and pass around references to that), and inspecting/modifying them at run-time is close to impossible. If you've got a reference to a sub wrapper for your decision tree, you can fake modifying it by installing additional wrappers around it. For example:
use 5.010;
my $standard_say = sub {
say 0 if $x ~~ [0..9, 50..59];
say 1 if $x ~~ [10..19, 60..69];
say 2 if $x ~~ [20..29, 70..79];
say 3 if $x ~~ [30..39, 80..89];
say 4 if $x ~~ [40..49, 90..99];
};
$standard_say->(40);
# Now imagine we decide to special-case 39...
my $modified_say = sub {
if ($_[0] == 39) {
say "yay!";
return;
}
$standard_say->(@_);
};
$modified_say->(40);
$modified_say->(39);
Doing something like that with Smart::Dispatch is a little cleaner...
use Smart::Dispatch;
my $standard_say = dispatcher {
match [0..9, 50..59], dispatch { say 0 };
match [10..19, 60..69], dispatch { say 1 };
match [20..29, 70..79], dispatch { say 2 };
match [30..39, 80..89], dispatch { say 3 };
match [40..49, 90..99], dispatch { say 4 };
};
$standard_say->(40);
my $modified_say = dispatcher { match 39, dispatch { say "yay!" } } .
+$standard_say;
$modified_say->(40);
$modified_say->(39);
perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
|