1. We have moved from vBulletin to XenForo and you are viewing the site in the middle of the move. Though the functional aspect of everything is working fine, we are still working on other changes including the new design on Xenforo.
    Dismiss Notice

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