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?
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
}
$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.)
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')
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.
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";
}
You can also use the smart match operator:
unless( $x ~~ ['value1','value2'] )
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")
Related
I have a scalar that may or may not be a reference to an array. If it is a reference to an array, I would like to dereference it and iterate over it. If not, I would like to treat it as a one-element array and iterate over that.
my $result = my_complicated_expression;
for my $value (ref($result) eq 'ARRAY' ? #$result : ($result)) {
# Do work with $value
}
Currently, I have the above code, which works fine but feels clunky and not very Perlish. Is there a more concise way to express the idea of dereferencing a value with fallback behavior if the value is not what I expect?
Just force it before the loop.
Limited, known ref type
my $result = *some function call* // [];
$result = [$result] if ref $result ne 'ARRAY';
for my $val ( #$result ){
print $val;
}
Ref type unknown
#!/usr/bin/perl
use 5.012;
use strict;
no warnings;
sub array_ref;
my $result = [qw/foo bar foobar/];
# $result = 'foo'; # scalar test case
# $result = {foo=>q{bar}}; # hash test case
$result = array_ref $result;
for my $val ( #$result ){
say $val;
}
sub array_ref {
my $ref = shift;
given(ref $ref){
$ref = [%$ref] when('HASH');
$ref = [$ref] when(['SCALAR','']);
when('ARRAY'){}
default {
die 'Did not prepare for other ref types';
}
}
return $ref;
}
This is for demo purposes (you shouldn't use given/when in production code), but shows you could easily test for the ref type and cast a new response. However, if you really don't know what type of variable your function is returning, how are you sure it's even a reference. What if it was an array or hash?
Being perl, there's going to be several answers to this with the 'right' one being a matter of taste - IMHO, an acceptable shortening involves relying on the fact that the ref function returns the empty string if the expression given it is scalar. This means you don't need the eq 'ARRAY' if you know there are only two possibilities (ie, a scalar value and an array ref).
Secondly, you can iterate over a single scalar value (producing 1 iteration, obviously), so you don't have to put the $result in parentheses in the "scalar" case.
Putting these two small simplifications togeather gives;
use v5.12;
my $result1 = "Hello World";
my $result2 = [ "Hello" , "World" ];
for my $result ($result1, $result2) {
for my $value ( ref $result ? #$result : $result) {
say $value ;
}
}
which produces;
Hello World
Hello
World
There's likely to be 'fancier' things you can do, but this seems a reasonable compromise between being terse and readable. Of course, YMMV.
I see that I'm late to this, but I can't help it. With eval and $#, and the comma operator
my $ra = [ qw(a b c) ];
my $x = 23;
my $var = $ra;
# my $var = $x; # swap comment to test the other
foreach my $el ( eval { #{$var} }, $# && $var )
{
next if $el =~ /^$/; # when #$var is good comma adds empty line
print $el, "\n";
}
Prints a b c (one per line), if we swap to my $var = $x it prints 23.
When $var has the reference, the $# is empty but the comma is still executed and this adds an empty line, thus the next in the loop. Alternatively to skipping empty lines one can filter them out
foreach my $el ( grep { !/^$/ } eval { #{$var} }, $# && $var )
This does, in addition, clean out empty lines. However, most of the time that is desirable.
sub deref {
map ref($_) eq 'ARRAY'? #$_ : ref($_) eq 'HASH'? %$_ : $_, #_
}
sub myCompExpr {
1, 2, 3, [4, 5, 6], {Hello => 'world', Answer => 42}
}
print $_ for deref myCompExpr
Why isn't the below code returning any output? I am expecting it to print out "Contains".
sub is_member {
my ($x, #list) = #_;
foreach (#list) {
if ($x eq $_) {"contains"} else {"doesn't contain"}
}
}
my #a = qw(apple x orange but so nos how dod to it a b c);
print is_member("apple",#a)."\n";
Like below code just run fine, outputting "is palindrome"
sub is_palindrome {
my ($x) = #_;
if ($x eq reverse($x)){"is palindrome"} else {"Not a palindrome"}
}
print is_palindrome("radar")."\n";
This code:
if ($x eq $_) {"contains"} else {"doesn't contain"}
does not print or return anything. It evaluates two constants, but that's all. I'm surprised there isn't a complaint about missing semicolons, too. And the indentation is eccentric.
You probably want something more like:
sub is_member
{
my ($x, #list) = #_;
foreach (#list)
{
return "contains" if ($x eq $_);
}
return "doesn't contain";
}
for loops do not have return values. In is_palindrome, the if statement is evaluated by itself which produces the return value for the subroutine implicitly.
In the case of the for loop, even if the last statement evaluated inside a for loop became the return value, the last comparison made, "apple" eq "c", would be false.
If you want to do the test using a for loop, you will need to exit the loop early. But, in Perl, grep is the built-in way to test if the elements of a list satisfy a condition.
my $result = (grep $_ eq $x, #list) ? "contains" : "does not contain";
print "'#list' $result $x\n";
If you are only interested in the existence of a certain element, List::MoreUtils::any
and List::MoreUtils::first_index provide performance advantages in case the list is long.
The conditional operator, $cond ? $t : $f, is more useful for writing compact conditionals than trying to fit an if statement on a single line with braces and all.
to clarify on the return values of subs, by default, Perl returns the value of the evaluation of the last expression in the sub... unless it's in a loop. from perldoc:
If no return is found and if the last statement is an expression, its
value is returned. If the last statement is a loop control structure
like a foreach or a while , the returned value is unspecified. The
empty sub returns the empty list.
but as others have stated, you should always use return if you are returning anything, for both readability and stability.
it's also true that your sub is unnecessary. grep will return 0 or 1 in a scalar context (that you can use as boolean), or a new array of matching values in an array context; ex:
my #a = qw(apple x orange but so nos how dod to it a b c);
print "found" if grep /^orange$/, #a; # prints "found"
my #b = grep length > 3, #a;
print "#b" # prints "apple orange"
Is it normal to write in such way:
if(($x && $y && $z) eq "test"){
}
If I am interested in ($x eq "test") && ($y eq "test") && ($z eq "test")?
It wouldn't be normal because it doesn't even work
$x && $y returns either $x or $y depending on whether the value of $x is true or not.
That means that ($x && $y) && $z returns either $x, $y or $z depending on the values of $x and $y.
That means that only one of $x, $y or $z will be compared against 'test'.
For example, you'll get a false positive (returns true when it should return false) when you have $x='abc'; $y='def'; $z='test';.
If you wanted something shorter, then you'd have to use something like
use List::MoreUtils qw( all );
if ( all { $_ eq "test" } $x, $y, $z )
No.
The expression $x && $y && $z is equivalent to the expression
$x ? $x : $y ? $y : $z
and will be evaluated separately from the expression on the other side of the eq operator.
Writing if ($x eq 'test' && $y eq 'test' && $z eq 'test') ... as you do is as reasonably terse as you're going to get.
As an elaboration on ikegami's answer, I thought I would show the code for the all() subroutine, as it is rather simple, and gives a good demonstration of the logic behind the answer to the question. And also, as it happens, makes a good demonstration for how prototypes work.
sub all (&#) {
my $f = shift;
foreach ( #_ ) {
return NO unless $f->();
}
return YES;
}
The prototypes & and # refer to a code reference, and a list of arguments. YES and NO are constants for true and false defined as follows:
# Use pure scalar boolean return values for compatibility with XS
use constant YES => ! 0;
use constant NO => ! 1;
The basic gist of this subroutine is to take a code reference (an anonymous subroutine) and execute it once for each argument, using $_ as the loop variable. If any argument causes the code block to return a false value, the subroutine returns false and ends.
With this code and these prototypes we can use the all subroutine much like map, with a code block first:
all { $_ eq "foo" } "foo", "bar", "baz";
If we remove the prototypes (&#), we must pass the code reference as a standalone, as part of the list:
all sub { $_ eq "foo" }, "foo", "bar", "baz";
Note the addition of the sub keyword, and the comma after the code block.
I have a Perl script where variables must be initialized before the script can proceed. A lengthy if statement where I check each variable is the obvious choice. But maybe there is a more elegant or concise way to check several variables.
Edit:
I don't need to check for "defined", they are always defined with an empty string, I need to check that all are non-empty.
Example:
my ($a, $b, $c) = ("", "", "");
# If-clauses for setting the variables here
if( !$a || !$b || !$c) {
print "Init failed\n";
}
I am assuming that empty means the empty string, not just any false value. That is, if 0 or "0" are ever valid values post-initialization, the currently accepted answer will give you the wrong result:
use strict; use warnings;
my ($x, $y, $z) = ('0') x 3;
# my ($x, $y, $z) = ('') x 3;
for my $var ($x, $y, $z) {
die "Not properly initialized\n" unless defined($var) and length $var;
}
Now, this is pretty useless as a validation, because, more than likely, you would like to know which variable was not properly initialized if this situation occurs.
You would be better served by keeping your configuration parameters in a hash so you can easily check which ones were properly initialized.
use strict; use warnings;
my %params = (
x => 0,
y => '',
z => undef,
);
while ( my ($k, $v) = each %params ) {
validate_nonempty($v)
or die "'$k' was not properly initialized\n";
}
sub validate_nonempty {
my ($v) = #_;
defined($v) and length $v;
}
Or, if you want to list all that were not properly initialized:
my #invalid = grep is_not_initialized($params{$_}), keys %params;
die "Not properly initialized: #invalid\n" if #invalid;
sub is_not_initialized {
my ($v) = #_;
not ( defined($v) and length $v );
}
use List::MoreUtils 'all';
say 'Yes' if (all { defined } $var1, $var2, $var3);
What do you mean by "initialized"? Have values that are not "undef"?
For a small amount of values, the straightforward if check is IMHO the most readable/maintainable.
if (!$var1 || !$var2 || !$var3) {
print "ERROR: Some are not defined!";
}
By the way, checking !$var is a possible bug in that "0" is false in Perl and thus a string initialized to "0" would fail this check. It's a lot better to use $var eq ""
Or better yet, space things out for >3 values
if (!$var1 # Use this if your values are guarantee not to be "0"
|| $var2 eq "" # This is a LOT better since !$var fails on "0" value
|| $var3 eq "") {
print "ERROR: Some are not defined!";
}
If there are so many values to check that the above becomes hard to read (though with per-line check as in the second example, it doesn't really ever happen), or if the values are stored in an array, you can use grep to abstract away the checking:
# We use "length" check instead of "$_ eq ''" as per tchrist's comment below
if (grep { length } ($var1, $var2, $var3, $var4, $var5, #more_args) ) {
print "ERROR: Some are not defined!";
}
If you must know WHICH of the values are not defined, you can use for loop (left as an obvious excercise for the reader), or a map trick:
my $i = -1; # we will be pre-incrementing
if (my #undefined_indexes = map { $i++; $_ ? () : $i }
($var1, $var2, $var3, $var4, $var5, #more_args) ) {
print "ERROR: Value # $_ not defined!\n" foreach #undefined_indexes;
}
use List::Util 'first';
if (defined first { $_ ne "" } $a, $b, $c) {
warn "empty";
}
Your way is readable and easy to understand which means it's easy to maintain. Restating your boolean using de Morgan's laws:
if (not($a and $b and $c)) {
warn(qq(Not all variables are initialized!))
}
That way, you're not prefixing not in front of every variable, and it doesn't affect readability. You can use List::Util or List::MoreUtils, but they don't really add to the legibility.
As Sinan Ünür stated, if you put the variables in a hash, you could parse through the hash and then list which variables weren't initialized. This might be best if there are a lot of these variables, and the list keeps changing.
foreach my $variable qw(a b c d e f g h i j) {
if (not $param{$variable}) {
warn qq(You didn't define $variable\n);
}
}
You can use Getopts::Long to put your parameter values inside a hash instead of separate variables. Plus, the latest versions of Getopts::Long can now operate on any array and not just #ARGV.
How does the || works in Perl? I want to achieve c style || operation.
#ARRAY=qw(one two THREE four);
$i=0;
if(($ARRAY[2] ne "three")||($ARRAY[2] ne "THREE")) #What's the problem with this
{
print ":::::$ARRAY[2]::::::\n";
}
while(($ARRAY[$i] ne "three")||($ARRAY[$i] ne "THREE")) #This goes to infinite loop
{
print "->$ARRAY[$i]\n";
$i=$i+1;
}
It works exactly the way you thought it would. However, you have a thinko in your condition. Every value is either not one value or not another value.
I believe you might have wanted
if ($ARRAY[2] ne 'three' && $ARRAY[2] ne 'THREE') { ...
or
if ($ARRAY[2] eq 'three' || $ARRAY[2] eq 'THREE') { ...
You might also want some case-insensitive way of comparing, like
if (lc $ARRAY[2] ne 'three') { ...
or possibly a case-insensitive regexp match.
Two general points. (1) Your Perl scripts should include use strict and use warnings. (2) In most situations, you can iterate directly over an array, avoiding subscripts entirely. An example:
use strict;
use warnings;
my #ARRAY = qw(one two THREE four);
for my $item (#ARRAY){
last if lc $item eq 'three';
print $item, "\n";
}
In ($ARRAY[2] ne "three") || ($ARRAY[2] ne "THREE") the || is a logical or, which means it returns true if at least one of the two expressions is true. Well, it checks the first one and if it is true, it even does not check the second one. And in this case the whole will be true anyway, since $ARRAY[2] cannot be equal to both strings.
Well, it is just like in C I believe. What would you like to achieve?
while(($ARRAY[$i] ne "three")||($ARRAY[$i] ne "THREE")) :
the expression $ARRAY[$i] ne "three" always evaluates to true. Therefore you have an infinite loop. The || operator has short-circuit behavior so the second expression is never evaluated.
($ARRAY[$i] ne "three") || ($ARRAY[$i] ne "THREE"))
This is going to be true in every case. It's either going to be not "three" or not "THREE". You want &&.