3

I'll be brief so I don't waste your time;

Simple problem, i have an array of say, hundreds of dogs

my @dogs = qw(Shepard Lab Dalmation Husky Chow Pitbull ...)

and i want to compare it to a single dog

my $doggy = "Shepard";

pretty stupid i know, but how would i do that?

# Regex match against array?
# (This doesnt even work but its how i would think of doing it)
if ($doggy =~ /@dogs/) {
print $doggy;
}

Thanks for any answers in advance, I appreciate you guys helping me with what is probably a really stupid question. Thank you

user1058357
  • 33
  • 1
  • 3
  • So, you want to "compare it to a single dog" - wouldn't that comparison always return false, as they're unequal? Or do you want to find the index of your dog in the list of dogs? Do you want to verify that your dog is listed? Please be a little more specific. – Nightfirecat Nov 21 '11 at 18:47
  • Yes, like you said, find my index of the dog, in the lists, so i can see if the shepard is in the master dog list or not – user1058357 Nov 21 '11 at 18:48
  • http://stackoverflow.com/questions/720482/how-can-i-verify-that-a-value-is-present-in-an-array-list-in-perl http://stackoverflow.com/q/1915746 http://stackoverflow.com/q/2383505 http://stackoverflow.com/q/2678503 http://stackoverflow.com/q/2925604 http://stackoverflow.com/q/3086874 http://stackoverflow.com/q/3222138 – daxim Nov 21 '11 at 19:57

7 Answers7

5

I would do it like this :

my %hDogs = map { $_ => 1 } @dogs;

if(exists($hDogs{$doggy})) { ... }
FailedDev
  • 26,680
  • 9
  • 53
  • 73
4

You can just use grep:

my @dogs = qw(Shepard Lab Dalmation Husky Chow Pitbull);
my @wanted_dogs = grep {/^Shepard$/} @dogs;
print "@wanted_dogs\n";

Result:

Shepard

The regex can be changed as wanted, and if you're only interested in the first matching dog, you'll find that in $wanted_dogs[0].

flesk
  • 7,439
  • 4
  • 24
  • 33
3

Smart match operator:

use warnings;
use strict;

my @dogs = qw(Shepard Lab Dalmation Husky Chow Pitbull);
my $doggy = "Shepard";
if ($doggy ~~ @dogs) {
    print $doggy;
}
toolic
  • 57,801
  • 17
  • 75
  • 117
2

Assuming you don't really want a regular expression match and just want to see if there is an exact match somewhere in the list, then you have a number of options.

Smart match is the relatively new, but simplest and possibly fastest approach.

The classic methods are grep and List::Util::first. You can adjust the latter two to use a regex instead of eq if you do want to (for example) match "Shepard" when $dog is "Shep".

use strict;
use warnings;
use v5.10;

my @dogs = qw(Shepard Lab Dalmation Husky Chow Pitbull);
my $dog = "Shepard";
my $cat = "Ocicat";

say "Smart match";
say $dog ~~ @dogs;
say $cat ~~ @dogs;

say "Grep";
say grep { $_ eq $dog } @dogs;
say grep { $_ eq $cat } @dogs;

say "List::Util";
use List::Util qw/first/;
say first { $_ eq $dog } @dogs;
say first { $_ eq $cat } @dogs;
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
1

There are techniques using the newer smart-match operator, but I prefer the old classic:

my $dogs_re = join '|' => map quotemeta, @dogs;

if ($doggy =~ /$dogs_re/) {...}

That creates a regex alternation of your dog types, after quoting any regex special characters in the names.

You could compile the regex as well if you want:

$_ = qr/$_/ for $dogs_re;  

which would be placed after the line defining $dogs_re, and may offer some performance benefits if you will be using the regex many times.

Eric Strom
  • 39,821
  • 2
  • 80
  • 152
  • 1
    This is a little hard to wrap my mind around, but im sure its a great solution, ill read it a few hundred more times :P, thank you for the response – user1058357 Nov 21 '11 at 18:55
  • Ahh ok i understand, itd be the equivalent of a regex with multiple match options : (Shepard|Husky|Chow), and then it could execute a regex statement, this is really useful as i will be re-using the regex hundreds of times and need to have it compiled for speed, Thanks much. – user1058357 Nov 21 '11 at 18:59
  • @user1058357 : Think about using a module that optimizes such regexes. Regexp::Assemble comes to mind – Zaid Nov 21 '11 at 19:09
  • @Zaid => Starting with 5.9.2, Perl's regex engine will automatically optimize chained alternations like this into a trie. – Eric Strom Nov 21 '11 at 19:57
  • `$dogs_re = qr/$dogs_re/` is shorter and more comprehensible, imho. – Eugene Yarmash Nov 21 '11 at 21:18
0

I would probably choose the hash lookup solution for best answer, but there are many ways to do this. This is one of them.

Note that this uses our dog name as the regex and iterates it over the list instead of the other way around.

use v5.10; # needed for say
@dogs=qw(Shepherd Lab Poodle Foo Bar); 
$dog = 'Lab'; 
/\Q$dog\E/i and say for @dogs;"

You can control how strict the match is:

/\Q$dog\E/i is least strict, ignore case, match anywhere in word. E.g. "lab" will match "Yellow Lab", "Labrador" etc.

/^\Q$dog\E$/ is most strict, match case, match entire word.

TLP
  • 66,756
  • 10
  • 92
  • 149
0

Try this,

$" = "|";
my @dogs=qw(Shepherd Lab Poodle Foo Bar);
my $temp = "@dogs";
my $dog = "Lab";
print "$1 found" if ($dog =~ /($temp)/);
Andro Selva
  • 53,910
  • 52
  • 193
  • 240