Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

boolean IN(); function in perl like

by Frank John (Acolyte)
on Jan 14, 2005 at 19:12 UTC ( #422347=perlquestion: print w/replies, xml ) Need Help??

Frank John has asked for the wisdom of the Perl Monks concerning the following question:

I have one element $e, one array of elements @a, is there any function to judge if $e in @a? Thx!

Replies are listed 'Best First'.
Re: boolean IN(); function in perl like
by Ovid (Cardinal) on Jan 14, 2005 at 19:17 UTC

    There are several ways to do this. One of the easiest is grep:

    if (grep {$_ eq $e} @a) { # $e is in @a }

    However, if this is done many times and/or if @a gets to be too large, a hash lookup can be useful:

    my %lookup = map { $_ => 1 } @a; # only do this once if you can if (exists $lookup{$e}) { # $e is in @a }

    Cheers,
    Ovid

    New address of my CGI Course.

      my %lookup = map { $_ => 1 } @a;

      There is no need to put values in the hash.

      my %lookup; @lookup{@a}=();

      Futhermode if @a is holding a set of data that is not conceptually ordered it is better to simply use a hash and not an array in the first place.

      One word of caution when using grep -- it will find all occurrences of $e in @a so if @a is large or there are a lot of occurrences of $e it will take longer than just looking for the first occurrence. You might also want to look at the any function in List::MoreUtils.
Re: boolean IN(); function in perl like
by ccn (Vicar) on Jan 14, 2005 at 19:20 UTC
Re: boolean IN(); function in perl like
by Anonymous Monk on Jan 14, 2005 at 19:16 UTC

    grep

    my @found = grep { $e eq $_ } @a; #or print "yes" if grep { $e eq $_ } @a;

      I'm surprised to see only grep examples with "eq". You can also do this with regex interpolation (being careful to match the whole thing, of course):

      print "found!" if grep(/^$e$/, @a);

      This might be useful if, for example, you didn't care about matching case:

      print "found!" if grep(/^$e$/i, @a);

      -xdg

      Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

        You'd better run $e through quotemeta if you do this, or use the equivalent \Q .. \E re syntax.

        (If case does matter, an eq check is definitely going to be faster. If it doesn't, precomputing lc $e and comparing that to lc $_ is still liable to be faster, though it's worth a benchmark. Of course, very often this is not a concern.)

Re: boolean IN(); function in perl like
by Limbic~Region (Chancellor) on Jan 14, 2005 at 19:31 UTC
Re: boolean IN(); function in perl like
by ikegami (Pope) on Jan 14, 2005 at 20:56 UTC
    If @a is sorted, you can use a binary search. It's very fast on long lists. For example, it does at most 14 compares if the array has 15,000 elements.

        If you mean it should be a module, I know, I know.

        And no, I write assembler for the Varian72 for these folks.

Re: boolean IN(); function in perl like
by Errto (Vicar) on Jan 14, 2005 at 19:18 UTC
    There certainly is. It's called grep. Sample code:
    my $count = grep { $_ eq $e } @a;
    Then $count will contain the number of occurrences of $e within @a.
Re: boolean IN(); function in perl like
by premchai21 (Curate) on Jan 15, 2005 at 06:01 UTC

    I'm surprised no one mentioned List::Util's "first" routine yet.

    first {$_ eq $e} @a

    I'm not sure this works properly if $e is undef, though.

      Or List::MoreUtil's even more correct 'any' function.
      if ( any { $_ eq $foo } @list ) { }
      If you are wondering why first isn't enough, imagine...
      if ( first { ! defined $_ } @list ) { # Does not get called if it matches } if ( any { ! defined $_ } @list ) { # Does get called it if matches }
      Of course, this assumes you only need to check once and once only. If you want to check many times, build the hash index and do it that way.

      Edit by castaway - swapped lotsa br tags for code tags

        Very right. ++ At a more basic level, this is why exists exists. Things may be there but have false values.

        Btw, please use <code> tags instead of <pre> tags when posting code. Cheers.

Re: boolean IN(); function in perl like
by Tanktalus (Canon) on Jan 14, 2005 at 19:15 UTC

    Not built-in. There are probably modules (look for Set::* modules on CPAN) that do it. I just use something like:

    sub s_in_a # scalar in array { my $s = shift; foreach (@_) { return 1 if $s eq $_; } 0; }

      Thx for the info and code. I can see "my $s =shift;" will take the first parameter passed to sun s_in_a; but I am not clear about @_ in "foreach (@_)", does @_ mean the array you pass in? Is it necessary to pass array by reference then dereferrence it? Thx, I appreciate it.

        Call it something like: s_in_a($scalar, @array_to_check) - no array references here.

        You're correct about @_. From the Perl Predefined Variables page: "Within a subroutine, the array @_ contains the parameters passed to that subroutine."

        /renz.
Re: boolean IN(); function in perl like
by Dr. Mu (Hermit) on Jan 16, 2005 at 03:53 UTC
    And if you want to know where in the array the element exists, try this find routine:
    use strict; my @a = qw/aaa bbc dde fff dde www/; my $e = 'dde'; print join(',', find($e, @a)), "\n"; sub find { my ($target, @array) = @_; grep {$array[$_] eq $target} (0 .. @array - 1) }
    which, in this example, returns:
    2,4
Re: boolean IN(); function in perl like
by blazar (Canon) on Jan 16, 2005 at 16:09 UTC
    I suspect that adding my cmt so late will not add to its visibility however a solution that I find to be semantically appealing is along the lines of:
    #!/usr/bin/perl -l use strict; use warnings; sub is { bless \shift, '_ghgh'; } sub _ghgh::in { my $x=${ shift, }; $x eq $_ and return 1 for @_; 0; } print is($_)->in(qw/foo bar baz/) ? 'yes' : 'no' for qw/bar fred/; __END__
Re: boolean IN(); function in perl like
by ccn (Vicar) on Jan 18, 2005 at 15:01 UTC

    I can't resist

    #!/usr/bin/perl -wl use strict; sub in { my $h = pop; @_ && ($h eq pop or in(@_, $h)) } my @a = qw(a b c d e f g h); print in(@a, $_) . " for $_ in (@a)" for qw(a c f v d s);
      I can't resist one either:
      if ( $e == any( @a ) ) { ... }
      What, Perl 6 isn't out yet? Never mind then...
      "There is a thin line between ignorance and arrogance, and only I have managed to erase that line." - Dr. Science
Re: boolean IN(); function in perl like
by mlh2003 (Scribe) on Jan 18, 2005 at 07:24 UTC
    Not sure, but what about a combination of join and index? I understand that both these functions are quite fast... Something like:
    sub s_in_a { my $s = shift; my $joined = '#' . join('#', @_) . '#'; if (index($joined, "#$s#") >= 0) { return 1; } else { return 0; } }
      You then have to be picky about a delimiter. If the data has #s in it, this breaks.
        Yes, that's correct. You'd have to know in advance what characters are used in the data set before choosing a delimiter. Sometimes it is known, sometimes not.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://422347]
Approved by Errto
Front-paged by traveler
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (2)
As of 2021-11-28 00:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?