http://www.perlmonks.org?node_id=371938

Purpose
On a regular basis, people want to know if a particular thing, we will call it foo, is present in an array. The problem with just directing them to perldoc -q contain is that each question usually varies enough to make a single answer unsatisfactory. The goal of this tutorial is to give enough information so that someone can choose the right solution to the problem.

Is This Tutorial For You?
A typical mistake is to assume that there is a built-in way of determining presence in an array like there is with a hash. A red flag should go up if you try using a string for an index as in print "gotcha\n" if $array['foo']. Perhaps you should be using a hash. An array gives no "meaning" between the index and the value (though the programmer might as in the case of matrices). If you are still unsure which to be using, see perldoc perldsc and perldoc perldata for more information.

What Will Be Covered
There are typically 5 answers to the problem of identifying if foo is present in an array.

There are a handful of things to consider and each solution has pros and cons accordingly. You will need to decide for yourself which is best.

Convert The Array To A Hash
Depending on your requirements, this can be a very attractive solution (print "It's in there\n" if exists $sauce{spaghetti}). There is a list of things to consider:

Use The Built-In grep
It is fast and powerful and deserves careful consideration:

Use List::Util's first
It works very much like grep except it returns on the first match, which depending on your situation can make it a perfect solution. It is worth noting that if it does not find a match, it returns undef which may be problematic if that's the value you are trying to match.

Use the smart match operator ~~ introduced in perl 5.10.0
If all you need to know is if an item is in the array or not, this may be the fastest solution. The smart match operator can do much more complicated matching, but since 5.10.0 is only a few days old this tutorial does not cover them.

IYAW (Invent Yet Another Wheel)
There is rarely a good reason to do this. Sanity checks such as profiling and benchmarking should be done before you spending valuable time trying to squeeze a couple of seconds off the runtime. I can only think of a couple of reasons you might want to do this:

Update: I modified the code snippet in the "Is This Tutorial For You" section to remove exists per rob_au's suggestion. It was not necessary to illustrate the point.

Update 2: 2004-10-02 - wolv pointed out to me that the inefficiencies in List::Util's first are in the pure perl version. The XS version is obviously much faster. Benchmark to be sure but it still loses to grep in many situations.

Update 3: 2007-12-22 - Added smart match operator section as a result of the release of perl 5.10.0. See this for a speed comparison.

Replies are listed 'Best First'.
Re: Getting Matching Items From An Array
by rob_au (Abbot) on Jul 05, 2004 at 23:58 UTC
    This is an excellent post Limbic~Region++. One note which I would make however is that the exists function can be of use with arrays where testing that an index is within the bounds of the defined array (without autovivifying a non-existent element) - This may be something useful which you can add to this text.

     

    perl -le "print unpack'N', pack'B32', '00000000000000000000001011100111'"

      rob_au,
      Instead of adding it, I have updated the node to remove exists in that section as it was not necessary. It did not occur to me that novices might see exists as improper with an array and total miss using a string as an index.

      While your point is well taken, I believe "Autovivication Pitfalls and How To Avoid Them" deserves to be a tutorial all to itself.

      Cheers - L~R

      exists still autovivifies in some situations:

      use Data::Dumper; my %h = ( foo => 1 ); print "Exists" if exists $h{bar}[2]; print Data::Dumper::Dumper \%h; __END__ $VAR1 = { 'bar' => [], 'foo' => 1 };

      Which probably isn't the right thing to do.

      ----
      send money to your kernel via the boot loader.. This and more wisdom available from Markov Hardburn.

        It should only autoviv that array element if the hash key is already defined IMHO...
      I'm not so sure there's a huge benefit here.
      my @x; $x[9] = 1; print "$#x ", scalar(@x), $/; print exists $x[2] ? 1 : 0, $/; print defined $x[2] ? 1 : 0, $/; + $x[2] = undef; print exists $x[2] ? 1 : 0, $/; print defined $x[2] ? 1 : 0, $/; ---- 9 10 0 0 1 0

      Basically, all you're saying is whether that element was assigned to. That's different from "Is this index within the bounds of the array?", which is tested by if ($i <= $#array).

      ------
      We are the carpenters and bricklayers of the Information Age.

      Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

      I shouldn't have to say this, but any code, unless otherwise stated, is untested