1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

in_array Functionality in Perl

Discussion in 'Perl' started by pradeep, Feb 21, 2008.

  1. pradeep

    pradeep Team Leader

    Joined:
    Apr 4, 2005
    Messages:
    1,646
    Likes Received:
    86
    Trophy Points:
    0
    Occupation:
    Programmer
    Location:
    Kolkata, India
    Home Page:

    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:
     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:
     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!
     
  2. oleber

    oleber New Member

    Joined:
    Apr 23, 2007
    Messages:
    37
    Likes Received:
    2
    Trophy Points:
    0
    Occupation:
    Software Developer (Perl, C/C++ and Java)
    Location:
    Hamburg, Germany
    Home Page:
    can I suggest other implementation?

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

    Code:
      sub in_array {
          my ($arr,$search_for) = @_;
         foreach my $value @$arr {
             return 1 if $value eq $search_for;
         }
         return 0;
     }
      
     
  3. pradeep

    pradeep Team Leader

    Joined:
    Apr 4, 2005
    Messages:
    1,646
    Likes Received:
    86
    Trophy Points:
    0
    Occupation:
    Programmer
    Location:
    Kolkata, India
    Home Page:
    Cool! I guess the first one you suggested would be more efficient than your 2nd suggestion and my sub-routine. What say?
     
  4. oleber

    oleber New Member

    Joined:
    Apr 23, 2007
    Messages:
    37
    Likes Received:
    2
    Trophy Points:
    0
    Occupation:
    Software Developer (Perl, C/C++ and Java)
    Location:
    Hamburg, Germany
    Home Page:
    Lets time this

    Code:
    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.

    :embarasse 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.

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

    :happy: The foreach stops when finds the first matching, so just half the match are needed in average.
     
  5. pradeep

    pradeep Team Leader

    Joined:
    Apr 4, 2005
    Messages:
    1,646
    Likes Received:
    86
    Trophy Points:
    0
    Occupation:
    Programmer
    Location:
    Kolkata, India
    Home Page:
    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 :)
     

Share This Page