How do I search a Perl array for a matching string?

204,327

Solution 1

I guess

@foo = ("aAa", "bbb");
@bar = grep(/^aaa/i, @foo);
print join ",",@bar;

would do the trick.

Solution 2

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::Util:

    use List::Util 1.33 '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.

Solution 3

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!"

Solution 4

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).

Solution 5

#!/usr/bin/env perl

use strict;
use warnings;
use Data::Dumper;

my @bar = qw(aaa bbb);
my @foo = grep {/aAa/i} @bar;

print Dumper \@foo;
Share:
204,327

Related videos on Youtube

Mike
Author by

Mike

I hate computers

Updated on February 29, 2020

Comments

  • Mike
    Mike about 4 years

    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")

    • Eric Strom
      Eric Strom almost 14 years
      how many times will you search the list?
    • Mike
      Mike almost 14 years
      it will only be searched once actually. runtime complexity isn't what i'm really worried about
    • osirisgothra
      osirisgothra almost 9 years
      not that it matters, or is in any way related, but if you kept your array in a set of hash keys (all with the value of 'whatever') you can find out if it exists or not much faster although case insensitivity does pose a problem...oh yeah and that ~~ smartmatch is slow as can be... otherwise, stick with Ether's well-documented answer that proves that the simplest answer isn't always the best answer, even if it is not from your point of view, the correct answer.
  • ysth
    ysth almost 14 years
    You are assuming "match" means regex match, but the example given is just (case insensitive) equality.
  • Zaid
    Zaid almost 14 years
    true is a bit overkill IMO. Is it faster than my $count = grep { /pattern/ } @list_of_strings; ?
  • Telemachus
    Telemachus almost 14 years
    @Zaid or even perldoc perlrequick first and then later perldoc perlreut
  • Vitali Pom
    Vitali Pom over 11 years
    Maybe: @bar = grep(/^aaa$/i, @foo); Since what you wrote will search all strings beginning with /aaa/i, so it will also find /aaaa/ and /aaaa+/.
  • zb226
    zb226 over 9 years
    This will cause false positives in certain situations, consider e.g. my @foo = ( "hello world hello bar" );
  • Admin
    Admin over 9 years
    Good observation about the false positives. Being aware of that, I find this nice and simple for single-word testing. If necessary, one could always add delimiter characters using join - for instance using \x01 would work for most text-strings.
  • osirisgothra
    osirisgothra almost 9 years
    Zaid and Telemachus: perlretquick and perlretut are both mentioned specifically in the very first paragraph in the description for perlre. It is the best to start off with because it presents the reader with a roadmap on how to proceed along the learning path. (unless you are either in a terminal with carpal tunnel syndrome or just hate clicking the mouse one extra time).
  • Bobby Adams
    Bobby Adams almost 9 years
    I think it would be more efficient to use grep {lc $_ eq 'aaa'}, @foo thus avoiding the need for RegEx processing.
  • Peter Tillemans
    Peter Tillemans almost 9 years
    All true, and very valid depending on the use-case. But I guess the examples given by the OP are only slightly representative for his issue.
  • Will Sheppard
    Will Sheppard over 8 years
    Please be aware that the smart match feature is experimental (source)
  • Dave Everitt
    Dave Everitt over 3 years
    Is it still experimental in 2020? There seems to be mixed opinions on whether or not to use it etc.: curiousprogrammer.wordpress.com/2010/06/15/…
  • Brian A. Henning
    Brian A. Henning almost 3 years
    Strawberry Perl 5.30 still emits "Smartmatch is experimental"...