Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Comparing multiple strings

by bigup401 (Pilgrim)
on Jan 15, 2019 at 16:26 UTC ( #1228599=perlquestion: print w/replies, xml ) Need Help??
bigup401 has asked for the wisdom of the Perl Monks concerning the following question:

How can i Compare multiple strings in faster way

$name = "john"; $t1 = "john"; $t2 = "john"; if ($name ne $t1 || $t2) { do something }

Replies are listed 'Best First'.
Re: Comparing multiple strings
by Eily (Prior) on Jan 15, 2019 at 16:50 UTC

    One way would be to put all the strings you want to match (or negative match) in a hash so that you can check for their existance:

    my @invalid_list = qw< John Simon Mathias Aerith Bob >; my @test = qw< Alice Bob John Doe >; my %invalid = map { $_ => 1 } @invalid_list; for my $name (@test) { print "$name\n" unless exists $invalid{$name}; }

    Or, as proposed by tobyink, you can use List::Util:

    use List::Util qw( none all any ); for my $name (@test) { print "None > $name\n" if none { $name eq $_ } @invalid_list; print "Any > $name\n" unless any { $name eq $_ } @invalid_list; print "All > $name\n" if all { $name ne $_ } @invalid_list; }
    (There's also notall, but it would have required a triple negation in this case).

Re: Comparing multiple strings
by tobyink (Abbot) on Jan 15, 2019 at 16:41 UTC

    Here's a few ways...

    If you're using a version of Perl that has smart match:

    if ($name ~~ [$t1, $t2]) { ...; }

    I've written match::smart which has a pure Perl implementation of smart match, which will allow you to do smart matching on older Perls:

    use match::smart "match"; if (match $name, [$t1, $t2]) { ...; }

    A lot of people don't like smart match though because the rules for exactly how it behaves are kind of confusing. match::smart comes bundled with match::simple which has saner rules and will also do what you're looking for:

    use match::simple "match"; if (match $name, [$t1, $t2]) { ...; }

    You can use List::Util's any function:

    use List::Util "any"; if (any { $name eq $_ } $t1, $t2) { ...; }

    match::simple has an optional XS implementation, match::simple::XS, and if you can install it, that will probably be faster than List::Util or match::smart.

      i have tried list util. but dont know the problem

      THIS DONT WORK $my1 = # IS "EV-1891" OR "EV-DKL1" thats wat we want; #THEN AM TRYING TO COMPARE IF NOT $my1 results if (any { $my1 ne $_ } 'EV-1891', 'EV-DKL1') { print "BAD"; last; } # MAKE OTHER NEXT CONDITION ACCESSIBLE IT ONLY WORKS WHEN I REMOVE 1 STRING THIS WORKS if (any { $my1 ne $_ } 'EV-1891') { print "BAD"; last; } # NEXT CONDITION ACCESSIBLE

      and my problem i want to compare two things ( if we dont get EV-DKL1 or EV-1891) show error

        Have you tried converting your attempts to plain English, and reading them to yourself? That may help you.

        if (any { $my1 ne $_ } 'EV-1891', 'EV-DKL1') { print "BAD"; last; }
        becomes "if any of a list of strings are not equal to my special string, then call the whole thing bad". When I say that out loud, it seems reasonable that your if would return true, and you would print "BAD", every time: your list of strings are not all the same string; so even if one is equal to $my1, the others aren't -- so "any" of them are "not equal to $my1", which means it will always print "BAD", unless your whole list are the same string, and match $my1.

        What you really seem to want is "call it bad unless there's at least one that does match". In that case, the logic could be: unless( any { $my1 eq $_ } 'EV-1891', 'EV-DKL1') { print "BAD"; last; }, or TIMTOWTDI, if( none { $my1 eq $_ } 'EV-1891', 'EV-DKL1') { print "BAD"; last; }

        and my problem i want to compare two things ( if we dont get EV-DKL1 or EV-1891) show error

        So you are saying you want all instead of any.

      thanks

Re: Comparing multiple strings
by LanX (Archbishop) on Jan 15, 2019 at 17:09 UTC
    @a == grep { 'string' eq $_ } @a

    because grep returns in scalar context the number of matches

    Demo
    DB<13> @a= ('string') x 5 DB<14> x @a 0 'string' 1 'string' 2 'string' 3 'string' 4 'string' DB<15> print @a == grep { 'string' eq $_ } @a 1 # true DB<16> push @a, 'nope' DB<17> print @a == grep { 'string' eq $_ } @a # false DB<18>

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: Comparing multiple strings
by rsFalse (Pilgrim) on Jan 16, 2019 at 11:17 UTC
    if ($name ne $t1 || $t2) { do something }
    Note that conditional will always be true if $t2 will be true, because '||' operator is lower in precedence than 'ne' (precedence list -- perlcheat). I guess OP asks maybe for 'shorter' (faster to write/maintain) way than $name ne $t1 || $name ne $t2.
    And is there a fast regex solution for this problem?
      ... a ... regex solution for this problem?

      Since the application seems to call for exact string matching, I would prefer a hash lookup or any-based solution as discussed already in this thread.

      But a regex solution might look like this:

      c:\@Work\Perl\monks>perl -wMstrict -le "my $t1 = 'EV-1891'; my $t2 = 'EV-DKL1'; ;; my ($rx_name_set) = map qr{ \A (?: $_) \z }xms, join '|', map quotemeta, reverse sort $t1, $t2 ; print $rx_name_set; ;; for my $name (@ARGV) { if ($name =~ $rx_name_set) { print qq{name '$name' in set}; } if ($name !~ $rx_name_set) { print qq{name '$name' NOT in set}; } } " EV-1891 FOO (?msx-i: \A (?: EV\-DKL1|EV\-1891) \z ) name 'EV-1891' in set name 'FOO' NOT in set
      Since the regex is  \A \z anchored for an exact match, the
          reverse sort
      step isn't really necessary, but it can't hurt. See Building Regex Alternations Dynamically. As to how fast it is, I leave that to your Benchmark-ing. My guess is that this approach should be fairly fast if you don't have to build the regex anew each time you do a set of comparisons; if you do, forget it.


      Give a man a fish:  <%-{-{-{-<

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1228599]
Approved by Athanasius
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (10)
As of 2019-02-19 15:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    I use postfix dereferencing ...









    Results (104 votes). Check out past polls.

    Notices?
    • (Sep 10, 2018 at 22:53 UTC) Welcome new users!