I learned something new this Friday. Some might frown and say that I should’ve known this from before, but I still have a long way to go before I fully master the Force. Say that we have an array filled with different values. For the example’s easiness, let’s say these values are from 1 to 2000, but they could be anything and don’t have to be in order at all.
my @allowed = (1 .. 2000);
The array define a range of allowed values in another array, which contain different, possible values. Again, for the example’s easiness, let’s say these are the values from 1 to 20000.
my @possibilities = (1 .. 20000);
Perl has a function grep to check whether or not a value is in an array, but if it has to check for every value we’re throwing at it, we’d end up with running it 18000 * 2000 + (2000 + 1999 + … + 1) amount of times. That’s 38 001 000 checks we have to toss in.
However, there is a simpler way. We can fill up a hash and check if it’s keys are defined. This would reduce the checks per miss from 2000 to 1. I knew this from before, but I’d been using a less awesome approach. Here’s what I’d do:
my %range;
for (@allowed) {
$range{$_} = 1;
}
While it’s quite okay, it doesn’t look very pretty to be tossing in that for loop in the middle of the code. This is where map comes in. The above code could be rewritten to:
my %range = map { $_ => 1 } @allowed;
That’s it! For every element of @allowed, map the the element’s value as a key in %range to the value 1. Quite nifty.
Let’s see our final code now:
# Let's assume these are given
my @allowed = (1 .. 2000);
my @possibilities = (1 .. 20000);
my %range = map { $_ => 1 } @allowed;
for (@possibilities) {
if (defined $range{$_}) {
# Let's do some stuff here
}
}
All in all, we’ve made the code prettier and we have reduced the amount of checks from the mind baffling 38 001 000 to merely 20 000. If it’s a hit or a miss, we have still only one check towards the hash. More optimized and fancy code. Awesome.