1

I have an array with two values and need to perform some operations if input is not in that array.

I tried like

if ($a ne ('value1' || 'value2')

if (($a ne 'value1' ) || ($a ne 'value2' ))

Both methods didn't work. Can anyone please help?

ysth
  • 96,171
  • 6
  • 121
  • 214
Futuregeek
  • 1,900
  • 3
  • 26
  • 51
  • 3
    You mention an array. I don't see an array in your code. If you really are working with an array this might help: http://stackoverflow.com/questions/2860226/how-can-i-check-if-a-perl-array-contains-a-particular-value – bloodyKnuckles Apr 29 '15 at 13:00

7 Answers7

7

You could use the none function from List::MoreUtils.

If you really have an array as your subject line says then your code would look like this

use List::MoreUtils 'none';

if ( none { $_ eq $a } @array ) {
  # Do stuff
}

or if you really have two constants then you could use this

if ( none { $_ eq $a } 'value1', 'value2' ) {
  # Do stuff
}

but in this case I would prefer to see just

if ( $a ne 'value1' and $a ne 'value2' ) {
  # Do stuff
}
Borodin
  • 126,100
  • 9
  • 70
  • 144
  • ++ I had never thought of this way but [`Smart::Match`](https://metacpan.org/pod/Smart::Match) operates like a "Util" module. It also has a `none` function where you would do: `if ( $x ~~ none (@array) ) {say "not here so do stuff"}`. It is almost as if it were acting like a `Match::Util` enhancement for a future (much simplified) version of the `~~` operator. Adding `Smart::Match` as a response. – G. Cito Apr 29 '15 at 15:14
  • 2
    @G.Cito: I like to give smart matching, or anything related to it, a very wide berth, and I dread having to write any quantity of code using the Perl 6 version. The problem is that it tries to be a *DWIM* operator and it's impossible to remember what it does with any given combination of parameters. I'd much sooner say what I mean and get the right result, as well as have others understand my code – Borodin Apr 29 '15 at 15:16
  • I can see how it may possibly be so "smart" that it will be difficult to simplify. Simplifying something can be complex, but it is taking a long while to get it right. – G. Cito Apr 29 '15 at 15:25
  • @G.Cito: In general, the *smart match operator* performs one of the functions available in `List::MoreUtils`. If you add to that the dereferencing of references then you pretty much have it covered, and each *different* operation has a different name as well, so you're not writing `$thing1 MAGIC $thing2` everywhere. Even object-oriented code can be problematic with such things, and that is about as far as I want to go – Borodin Apr 29 '15 at 15:40
5

$a is not in the array if it's different to the first element and it's different to the second one, too.

if ($x ne 'value1' and $x ne 'value2') {

For a real array of any size:

if (not grep $_ eq $x, @array) {

(I use $x instead of $a, as $a is special - see perlvar.)

choroba
  • 231,213
  • 25
  • 204
  • 289
  • 2
    reserve and for flow control; use && in expressions – ysth Apr 29 '15 at 13:59
  • 1
    You should avoid using `grep` for this: https://metacpan.org/pod/release/THALJEF/Perl-Critic-1.125/lib/Perl/Critic/Policy/BuiltinFunctions/ProhibitBooleanGrep.pm – Vadim Pushtaev Apr 29 '15 at 21:24
  • 1
    @VadimPushtaev That is certainly valid when you're checking if something *is* in an array, but in this case, we're checking if something is *not* in an array, which necessarily requires iterating through every single element. You could use `grep` or `List::MoreUtils::none`, pick your poison. – ThisSuitIsBlackNot Apr 29 '15 at 23:31
  • 1
    @ThisSuitIsBlackNot, no, that's wrong. `none` doesn't necessarily iterate through every single element, it stops after the first match, just like `any`. – Vadim Pushtaev Apr 30 '15 at 05:39
  • @VadimPushtaev Ah, you're right. You only have to iterate through every element if there are no matches. – ThisSuitIsBlackNot Apr 30 '15 at 11:19
4
if ($a ne ('value1' || 'value2')

evaluates to

if ($a ne 'value1')

and

if (($a ne 'value1' ) || ($a ne 'value2' ))

is always TRUE.

You might try

if ($a ne 'value1' and $a ne 'value2')

or

if (!grep{$a eq $_} 'value1', 'value2')
mpapec
  • 50,217
  • 8
  • 67
  • 127
  • You should avoid using `grep` for this: https://metacpan.org/pod/release/THALJEF/Perl-Critic-1.125/lib/Perl/Critic/Policy/BuiltinFunctions/ProhibitBooleanGrep.pm – Vadim Pushtaev Apr 29 '15 at 21:24
  • 1
    @VadimPushtaev: I think *should avoid* is overstating it. This is simply one of the edicts of *Perl Best Practices*, and the reason is that `grep` compares *all* elements of the list, regardless of whether an earlier match could short-circuit the process. As long as this is borne in mind, `grep` is a fine way of doing this, especially since the list is only two items in length, and the extra computing would be insignificant in any code that also reads data from a disk file – Borodin Apr 30 '15 at 15:38
1

Building on the smartmatch solution by @Dilbertino (nice nick) using match::simple by @tobyink to ease the pain of smartmatch going away (I miss it already):

use match::simple;
my @array = qw(abcd.txt abcdeff.txt abcdweff.txt abcdefrgt.txt);
my $x="abcd.txt" ;
say "it's there" if ($x |M| \@array );

The |M| operator from match::simple can be replaced with a match function which speeds things up a bit (it is implemented with XS):

use match::simple qw(match);
my @array = qw(abcd.txt abcdeff.txt abcdweff.txt abcdefrgt.txt);
my $x="xyz.txt" ;

if ( match ( $x, \@array ) ) {
     say "it's there!" ;
}
else {
     say "no hay nada";
} 

It's "simple" because the RHS controls the behavior. With match::simple if you are matching against an array on the RHS it should be an arrayref.

Smart::Match also has a none function. To use it you would do:

if ( $x ~~ none (@array) ) { 
   say "not here so do stuff ..."; 
}

Appendix

Discussion here on Stackoverlfow (see: Perl 5.20 and the fate of smart matching and given-when?) and elsewhere (c.f. the Perlmonks article by @ikegami from circa perl-5.18) gives the context for the smartmatch experiment. TLDR; things might change in the future but meanwhile, you can go back in time and use match::smart qw(match); with perl-5.8.9 proving once again that perl never dies; it just returns to its ecosystem.

In the future something like Smart::Match (i.e. the non-core CPAN module not the concept) can help supercharge a simplified smart matching operator with helper functions that read like adverbs and adjectives and have the added bonus (as I understand it) of clarifying/simplifying things for perl itself since the ~~ operator will have a less ambiguous context for its operations.

Community
  • 1
  • 1
G. Cito
  • 6,210
  • 3
  • 29
  • 42
  • 1
    The topic hasn't come up again on p5p since those posts of mine. Someone interested needs to step up – ikegami Apr 29 '15 at 15:38
1

I would do something like this using grep with a regex match

#!/usr/bin/perl
use warnings;
use strict;

my @array = ('value1','value2');

if(grep(/\bvalue1\b|\bvalue2\b/, @array)){
    print "Not Found\n";
}
else {
    print "do something\n";
}
Ed Dunn
  • 1,152
  • 3
  • 11
  • 27
  • You should avoid using `grep` for this: https://metacpan.org/pod/release/THALJEF/Perl-Critic-1.125/lib/Perl/Critic/Policy/BuiltinFunctions/ProhibitBooleanGrep.pm – Vadim Pushtaev Apr 29 '15 at 21:24
0

You can also use the smart match operator:

unless( $x ~~ ['value1','value2'] )

  • I for one am going to miss "`~~`" if/when it goes away. There's always [`match::simple`](https://metacpan.org/pod/match::simple) by @tobyink. – G. Cito Apr 29 '15 at 13:35
  • 2
    Just to clarify @G.Cito's comment vis-a-vis smartmatch going away...smartmatch was [marked experimental in 5.18.0](http://perldoc.perl.org/perl5180delta.html#The-smartmatch-family-of-features-are-now-experimental): "It is clear that smartmatch is almost certainly either going to change or go away in the future. Relying on its current behavior is not recommended." – ThisSuitIsBlackNot Apr 29 '15 at 15:10
  • @ThisSuitIsBlackNot Thanks, I tried to clarify it a bit more in my response. Channeling p5p perlmonks and @ikegami @leont it seems we can maybe hope for a much simpler version of `~~` in future versions of Perl - the behavior of which could be enhanced and extended with a utility module and the CPAN ecosystem. /me crosses fingers – G. Cito Apr 29 '15 at 15:20
-1

Your variable $a is not evaluated as a array without [INDEX] index, but is been treated as a scalar.

Two value array:

$array[0] = "X"; $array[1] = "Y";

or

@array = qw/X Y/;

Condition check using if:

if ( $array[0] ne "Your-String" || $array[1] ne "Your-String")

VAR121
  • 512
  • 2
  • 5
  • 16
  • I think the way the sample code is presented assumes an `@array` somewhere which the value of `$a` is matching against. It's not the clearest example code but the OP should be the one to change it. – G. Cito Apr 29 '15 at 15:46