What is the smartest way of searching through an array of strings for a matching string in Perl?
One caveat, I would like the search to be case-insensitive
so "aAa"
would be in ("aaa","bbb")
What is the smartest way of searching through an array of strings for a matching string in Perl?
One caveat, I would like the search to be case-insensitive
so "aAa"
would be in ("aaa","bbb")
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my @bar = qw(aaa bbb);
my @foo = grep {/aAa/i} @bar;
print Dumper @foo;
print "\n";
I guess
@foo = ("aAa", "bbb");
@bar = grep(/^aaa/i, @foo);
print join ",",@bar;
would do the trick.
It depends on what you want the search to do:
if you want to find all matches, use the built-in grep:
my @matches = grep { /pattern/ } @list_of_strings;
if you want to find the first match, use first
in List::Util:
use List::Util 'first';
my $match = first { /pattern/ } @list_of_strings;
if you want to find the count of all matches, use true
in List::MoreUtils:
use List::MoreUtils 'true';
my $count = true { /pattern/ } @list_of_strings;
if you want to know the index of the first match, use first_index
in List::MoreUtils:
use List::MoreUtils 'first_index';
my $index = first_index { /pattern/ } @list_of_strings;
if you want to simply know if there was a match, but you don't care which element it was or its value, use any
in List::MoreUtils:
use List::MoreUtils 'any';
my $match_found = any { /pattern/ } @list_of_strings;
All these examples do similar things at their core, but their implementations have been heavily optimized to be fast, and will be faster than any pure-perl implementation that you might write yourself with grep, map or a for loop.
Note that the algorithm for doing the looping is a separate issue than performing the individual matches. To match a string case-insensitively, you can simply use the i
flag in the pattern: /pattern/i
. You should definitely read through perldoc perlre if you have not previously done so.
If you will be doing many searches of the array, AND matching always is defined as string equivalence, then you can normalize your data and use a hash.
my @strings = qw( aAa Bbb cCC DDD eee );
my %string_lut;
# Init via slice:
@string_lut{ map uc, @strings } = ();
# or use a for loop:
# for my $string ( @strings ) {
# $string_lut{ uc($string) } = undef;
# }
#Look for a string:
my $search = 'AAa';
print "'$string' ",
( exists $string_lut{ uc $string ? "IS" : "is NOT" ),
" in the array\n";
Let me emphasize that doing a hash lookup is good if you are planning on doing many lookups on the array. Also, it will only work if matching means that $foo eq $bar
, or other requirements that can be met through normalization (like case insensitivity).
Perl 5.10+ contains the 'smart-match' operator ~~
, which returns true if a certain element is contained in an array or hash, and false if it doesn't (see perlfaq4):
The nice thing is that it also supports regexes, meaning that your case-insensitive requirement can easily be taken care of:
use strict;
use warnings;
use 5.010;
my @array = qw/aaa bbb/;
my $wanted = 'aAa';
say "'$wanted' matches!" if /$wanted/i ~~ @array; # Prints "'aAa' matches!"