in_array Functionality in Perl

pradeep's Avatar author of in_array Functionality in Perl
This is an article on in_array Functionality in Perl in Perl.

Introduction



One of the strengths of PHP when it comes to arrays is considered to be the in_array function (http://php.net/in_array), this function takes two parameters; the array and the item to be searched in the array and then returns a boolean result whether the item exists in the array. Perl inherently lacks this functionality, even popular Perl modules like List::Util lack such a function/method.

As it was said by Plato once, "Necessity... the mother of invention.", I required to check whether a name existed in an array, bored by using conventional method of iterating the array every time I need to check, I wrote a simple sub-routine to get the job done.

This sub-routine take two arguments, a reference to the array to be searched, and the item that needs to be searched. Simple enough the sub-routine works like magic, even my friend have found it very useful. I thought may be someone might find it useful, here's it, take a look.

Code: Perl
sub in_array
 {
     my ($arr,$search_for) = @_;
     my %items = map {$_ => 1} @$arr; # create a hash out of the array values
     return (exists($items{$search_for}))?1:0;
 }

Sample Usage



Code: Perl
my @arr = ('Amlan','Pradeep','Shency','Shabbir');
 
 
 sub in_array
 {
     my ($arr,$search_for) = @_;
     my %items = map {$_ => 1} @$arr;
     return (exists($items{$search_for}))?1:0;
 }
 
 if(in_array(\@arr,'Amlan'))
 {
     print "Hurray! Amlan you are in!!\n";
 }
 else
 {
     print "Ooops! Amlan you are out!!\n";
 }

Output :



Code:
 [pradeep@go4expert ~]$ ./amlan_test.pl
 Hurray! Amlan you are in!!
 [pradeep@go4expert ~]$
I guess the code is self-explanatory for everyone to understand. Enjoy!
oleber's Avatar, Join Date: Apr 2007
Go4Expert Member
can I suggest other implementation?

Code: Perl
sub in_array {
     my ($arr,$search_for) = @_;
     return grep {$search_for eq $_} @$arr;
}

or

Code: Perl
sub in_array {
      my ($arr,$search_for) = @_;
     foreach my $value @$arr {
         return 1 if $value eq $search_for;
     }
     return 0;
 }
pradeep's Avatar, Join Date: Apr 2005
Team Leader
Cool! I guess the first one you suggested would be more efficient than your 2nd suggestion and my sub-routine. What say?
oleber's Avatar, Join Date: Apr 2007
Go4Expert Member
Lets time this

Code: Perl
use Benchmark qw(:all) ;

sub in_array_pradeep {
    my ($arr,$search_for) = @_;
    my %items = map {$_ => 1} @$arr;
    return (exists($items{$search_for}))?1:0;
}

sub in_array_1 {
    my ($arr,$search_for) = @_;
    return grep {$search_for eq $_} @$arr;
}

sub in_array_2 {
    my ($arr,$search_for) = @_;
    foreach my $value (@$arr) {
        return 1 if $value eq $search_for;
    }
    return 0;
}

my @arr = qw(Amlan Pradeep Shency Shabbir oleber or use subroutine references timethese benchmark running times of Perl code);

timethese(100000,
{
    'in_array_pradeep' => sub {in_array_pradeep(\@arr, $_) foreach @arr},
    'in_array_1' => sub {in_array_1(\@arr, $_) foreach @arr},
    'in_array_2' => sub {in_array_2(\@arr, $_) foreach @arr},
});

and the results in my machine are:

Code:
Benchmark: timing 100000 iterations of in_array_1, in_array_2, in_array_pradeep...
in_array_1:  5 wallclock secs ( 5.34 usr +  0.00 sys =  5.34 CPU) @ 18726.59/s (n=100000)
in_array_2:  5 wallclock secs ( 4.48 usr +  0.00 sys =  4.48 CPU) @ 22321.43/s (n=100000)
in_array_pradeep: 32 wallclock secs (32.13 usr +  0.00 sys = 32.13 CPU) @ 3112.36/s (n=100000)
Now lets speak about the results.

The solution of pradeep is very slow. This seems obvious since he is creating a big structure in memory.

Now the other two are interesting.

The grep is fast since runs in C code inside the machine, but has to check all the elements.

The foreach stops when finds the first matching, so just half the match are needed in average.
pradeep's Avatar, Join Date: Apr 2005
Team Leader
Hi oleber, I saw your post today! Good finding, even I was wondering that my sub-routine wasn't very efficient. And today only I figured out that using grep would be better, but I see that you have already posted it :-)