The quest for The Element
30 June 2010
Scenario: You have this data structure X, and need to know if string Y might be
hiding in there somewhere.
This happens all the time, and is probably what you will keep on repeating over
and over again, for different purposes.
Let’s take a look at how we can do this in some interesting ways.
There Is More Than One Way To Do It
If you simply need to know if an element exists, you can use the smart-match
operator introduced in Perl 5.10:
my @array = qw(foo bar baz);
print 1 if 'bar' ~~ @c;
If you need to grab the first element that matches evaluated pattern, you can
use the ‘first’ function from the core List::Util module:
use List::Util 'first';
my @array = qw(foo bar baz);
print first{m/ba./} @array; # will print 'bar'
You are not limited to regular expressions, either:
use Data::Dumper;
use List::Util 'first';
my @array = (undef, 'foo', undef, 'bar');
print Dumper first{!defined($_)}; # $VAR1 = undef;
print Dumper first{defined($_)}; # $VAR1 = 'foo';
my @ints = (0..15);
print first{$_ > 10} @ints; # 11
The first function works on hashes as well, and maybe it’s first here were we’ll
see how useful it can be.
Instead of manually looping through the hash if you’re interested in the key for
a specific value, you can do it like this:
use List::Util 'first';
my %hash = (
foo => 'bar',
perl => 'awesome',
);
# print the first key that responds to the value of 'awesome'
print first{$hash{$_} eq 'awesome'} @hash; # prints 'perl'
# print the first key which length is more or equal to four
print first{length($hash{$_}) >= 4} %hash; # prints 'perl'
So the first function is pretty useful, but it wont do any good if we’re
interested in several values. Here is where grep comes in to play.
Those that are familiar with the grep command from Gnu/Linux and UNIX
environments are probably using it everyday, and for good reason.
grep() in Perl is not the same, but similar in spirit. Let’s take a look:
my @numbers = (0..15);
print "$_\n" for(grep($_ > 5, @numbers)); # prints 6..15
my @shuffled = qw(4 foo 593 bar 22);
# Grab the numbers
print "$_\n" for(grep{/\d+/} @shuffled; # prints 4, 593, 22
Sidenote: \d matches a single character that’s considered to be a digit.
Digits are not necessarily 0-9 – it depends on the encoding of the source string
and the LOCALE that’s in effect. It’ll happily match indian devanagardi numerals
as well; therefore it might be a good idea to use [0-9] if you suspect that you
might deal with more exotic things.