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 &&.
Related
For example, could I write something like:
my $var = "A" || "B";
where ($var eq "A") and ($var eq "B") would both evaluate to true? If not, is there some way around this?
Are you looking for Quantum::Superpositions?
Update: An example.
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Quantum::Superpositions;
my $var = any('A', 'B', 'C');
for ('A', 'B') {
if ($var eq $_) {
say "\$var equals $_";
} else {
say "\$var doesn't equal $_";
}
}
Output:
$var equals A
$var equals B
$var doesn't equal C
EDIT:
From what I've gathered from your comments and previous question you have a string with chars and just want to check if one char is inside of it. Instead of constructing something like $var = "A" || "B" (which doesn't work) you can simply check if the needed char is in the string (with a simple regex):
$var = "AB";
if ($var =~ /A/) { # True
# Calculations
}
if ($var =~ /B/) { # Also true
# Other calculations
}
You cannot. It sounds like you misunderstand logical operator and bitwise operator.
| is bitwise operator, it works on bits.
|| is logical operator
From what you say, I presume you need logical operator, but be more specific.
You can get some help there: http://www.perlmonks.org/?node_id=301355
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")
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"
I have a question on efficiency and readability in perl
I have a variable that can take on one of several values (5-6). Sometimes I want to check if this is a specific value, sometimes I want to check if it is one of several choices. I am making this sort of decision in many places in my code (in different functions), and I would like to make this as 'tight' as possible.
for example, say
my $mode; # can be any of qw(one two three four five six)
if ($mode eq 'one') {
#do code
}
if ($mode eq 'one' or $mode eq 'two' or $mode eq 'three') {
#do more code
}
This of course is not my real code, and with meaningful variable names, my if statements are getting quite long and wrap on several lines.
Any help is appreciated!
The List::MoreUtils module has the any function, which is like a short-circuiting grep:
use List::MoreUtils qw/any/;
say "correct mode" if any { $_ eq $mode } qw/one two three/;
That said, you can still use grep, but that always tests all elements, whereas any aborts after the first matching element:
say "correct mode" if grep { $_ eq $mode } qw/one two three/;
An idea.
my %please_name_me;
$please_name_me{$_}++ for qw(one two three);
if ($please_name_me{$mode}) {
#do something
}
Otherwise I like using whitespace:
if (
'one' eq $mode or
'two' eq $mode or
'three' eq $mode
) {
}
This would be a nice job for smart match, but the operator has been marked experimental and may be removed from later versions of Perl.
List::Util has the any operator. However, be very careful. The List::Util is a standard Perl module since at least Perl 5.8.8. Unfortunately, the nice any operator isn't included. You need to update this module in order to use any. However, the first operator may be good enough and that's part of the package:
use strict;
use warnings;
use feature qw(say);
use autodie;
use List::Util qw(first);
use constant VALID_VALUES => qw(one two three four five);
for my $value ( qw(zero one two three four five six) ) {
if ( first { $value eq $_ } VALID_VALUES ) {
say "$value is in the list!";
}
else {
say "Nope. $value is not";
}
}
Since you have use List::Util qw(first); in your program, user should realize that first is from the List::Util package and they can use perldoc List::Util to look it up.
You can also just use grep and forget about List::Util:
for my $value ( qw(zero one two three four five six) ) {
if ( grep { $value eq $_ } VALID_VALUES ) {
say "$value is in the list!";
}
else {
say "Nope. $value is not";
}
}
What you shouldn't do is use a complex regular expression or a if/else chain. These aren't necessarily any clearer and make your program harder to understand:
if ( $value =~ /^(one|two|three|four|five)$/ ) {
if ( $value eq "one" or $value eq "two" or $value eq "three" ... ) {
If you decide to change the valid list of values, you would have to go through your entire program to search for them. This is why I made them a constant. There's only one place in the program where they have to be modified.
There are a number of options (TMTOWDI). Here are two of the simplest:
if ($mode =~ /^(?one|two|three)$/) { ... }
if (grep { $mode eq $_ } qw(one two three)) { ... }
With a little setup beforehand you can make it rather more efficient. Do this once:
my #modes = qw(one two three);
my %modes;
#modes{#modes} = #modes;
Then your check becomes simply:
if ($modes{$mode}) { ... }
If you're using Perl 5.10 or later, you can use smart match operator:
if ($mode ~~ ['one', 'two', 'three'])
If you have many, many combinations to check, consider translating $mode to a numbered bit:
if 'one' -> $modeN = 1
if 'two' -> $modeN = 2
if 'three' -> $modeN = 4 etc.
To check just 'one', if ($modeN == 1) {...
To check 'one', 'two', or 'three', if ($modeN & 7) {...
To check 'two' or 'three', if ($modeN & 6) {...
To check 'one' OR ('two' AND 'three'), if ($modeN & 1 || &modeN & 6) {...
Does that work for you?
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.