Monday, September 21, 2009

pythonic perl 4: Finding an element in a list

In Python, you can do this:

a = "findme"
mylist = [ "no", "notthis",
"findme", "toomany",
"not here" ]

if a in mylist:
print "Found it!"
print "D'oh! Didn't find it."

True to its roots, there is more than one way to do this in Perl. The more common ways would be to use an array (the semantic equivalent of a Python list) and grep.

But the most Pythonic way I found would be not to use an array but to use a hash. Note that the mapped values are arbitrary and are not really used. In fact, you probably don't need to define any values since we are using exists and not the defined function.

$a = "findme";
%myhash = (
"no" => 0,
"notthis" => 1,
"gettingwarmer" => 2,
"findme" => 3,
"toomany" => 4,
"not here" => 6,

if (exists $myhash{$a)) {
print "Found it!\n";
} else {
print "D'oh! Didn't find it.";

More Perl articles:


Dave Doyle said...

If you're using Perl 5.10 you can also use the smart match operator.

my @array = ('whoo','hoo','foo','bar');

if ( 'foo' ~~ @array) {
say "Found it!";
else {
say "It ain't there!";

Naveed said...

Here is a nicer way to do it in perl.

my $a = "findme";
my @list = ("no", "notthis", "gettingwarmer", "findme", "toomany", "not here");
print $a ~~ @list ? "Found it!\n" : "D'oh! Didn't find it.\n";

Daniel Ruoso said...


First of all, congrats for this series of posts. Suggesting improvements and practices is the best way to send a message.

A lot of Perl programmers do avoid $_ most of the time (I do), but it's nice to have it there for things like: "print for 1..5".

But the point of my comment is directed to the "search item in list" problem. I didn't get why you think using a different data structure gives you a more "pythonic" code.

The code I'd write is:

if (grep { $_ eq $a } @l) { ...

Ok, you might thing the use of $_ is "non-pythonic"... so let me try to get you a different version...

... grep /^$a$/ @l ...

Ok, it uses a regular expression, but that's not really problematic, is it?

But let's say you don't like that as well. Let's assume you're using perl 5.10 (which is out for a while already), you can simply...

my $a = 'findme';
my @l = qw(no notthis gettingwarmer findme toomany nothere);

if ($a ~~ @l) {
print "Found it\n";
} else {
print "D'oh! Didn't find it";

raoul said...

Thanks all for the suggestions. I definitely did not know about the "~~" operator.

Given the choice between grep and ~~, I think I will go with ~~. I will have to read more about it though.

Dave, Naveed, and Daniel: thanks for the suggestions. I will post more about this.