I have some piece of code for multiple conditions in Perl
if (/abc/ && !/def/ && !/ghi/ && jkl) {
#### do something
}
Will every condition will be evaluated at once on every line?
I can prioritize the conditions using nested ifs
if (/abc/){
if (!/def/){
....so on
}
&& short-circuits. It only evaluates its RHS operand if needed. If it's LHS operand returns something false, && will that value.
For example,
use feature qw( say );
sub f1 { say "1"; 1 }
sub f2 { say "2"; 0 }
sub f3 { say "3"; 0 }
sub f4 { say "4"; 0 }
1 if f1() && f2() && f3() && f4();
Output:
1
2
So the following two lines are basically the same:
if (/abc/) { if (!/def/) { ... } }
if (/abc/ && !/def/) { ... }
In fact, if compiles into an and operator, so the above are very close to
(/abc/ and !/def/) and do { ... };
(/abc/ && !/def/) and do { ... };
No.
Think of it like this, if I said
"is the moon bigger than the sun?"
AND "is the pacific bigger than the mediterraan?"
AND "is russia bigger than england?"
AND ... many more AND ....
You could answer "no" very quickly, not having to figure out the answer to anything beyond the first question. It's called "short circuiting"
So in your case, unless an input line matches
/abc/ && !/def/ && !/ghi/
You won't need to evaluate whether it matches /jkl/.
Related
Consider the following rule for "locations" r and s:
∀r,s[(danger(r)∧adjacent(r,s))→danger(s)]
I tried to implement as follows:
function boolean adjacent(Location l1, Location l2) {
if (l1.x == l2.x)
return Math.abs(l1.y - l2.y) == 1;
if (l1.y == l2.y)
return Math.abs(l1.x - l2.x) == 1;
return false;
}
rule danger
when
$s : Location(danger == true)
$r : Location()
adjacent($s,$r)
then
modify($r) { setDanger(true) }
end;
But it does not compile saying that adjacent cannot be resolved.
I tried eval(adjacent($s,$r)) but it does not work because rete keeps visiting the same combinations of $s and $r forever.
I tried implementing adjacent() method on Location, but it does not compile either:
$r : Location(adjacent($s) == true)
I thought on some alternatives like: making each Location has a list of adjacent locations; etc. But none of them sounded right for me.
How would be the right way to implement this?
rule danger
when
$s : Location( danger )
$r : Location(! danger, adjacent($s,$r) )
then
modify($r) { setDanger(true) }
end
You can write a boolean expression as a constraint, or inside an eval CE (but never as a pattern all by itself, as you tried).
To avoid the loop, add a constraint that fails after the modify.
7 foreach (#crons) {
8 unless (index($_, "cks") != -1) {
9 unless (index($_, "aab") != -1) {
10 unless (index($_, "lam") != -1) {
11 push (#found, $_);
12 }
13 }
14 }
15 }
how come the above does not give the same output as the following:
7 foreach (#crons) {
8 unless (index($_, "cks") != -1 && index($_, "aab") != -1 && index($_, "lam") != -1) {
9 push (#found, $_);
10 }
11 }
#crons has the list of strings and I am trying to get all string that does not have "cks", "aab" and "lam"
The first section of code does what i want but the second doesnt and in my mind, it should...
Can anyone care to explain why they are not the same nor why it does not give the same output?
Let's call your conditions A, B, C. We now have the code
unless (A) {
unless (B) {
unless (C) {
The unless can be very confusing, so we write it only using if:
if (!A) {
if (!B) {
if (!C) {
Now we && those conditions together:
if (!A && !B && !C) {
This could also be written as
if (not(A || B || C)) {
This equivalence is called de Morgan's law
The non-equivalence of the two logics become clear when you test the string 'cks'.
The first logic would evaluate to false, the second would evaluate to true, since it does not contain the string 'aab' or 'lam'.
Let's say we have a description field on my form with optional check boxes. The check boxes represent which fields to search when doing the lookup. Right now I have a matrix of look ups that call their unique version of where clause. It works but I think it smells a bit.
Here is an excerpt
// Look for part numbers decide how many fields to search and use that one.
// 0 0 X
if (!PartOpt[0] && !PartOpt[1] && PartOpt[2])
{
query = query.Where(p => (p.PartNumAlt2.Contains(partSearchRec.inventory.PartNum)));
}
// 0 X 0
if (!PartOpt[0] && PartOpt[1] && !PartOpt[2])
{
query = query.Where(p => (p.PartNumAlt.Contains(partSearchRec.inventory.PartNum)));
}
// 0 X X
if (!PartOpt[0] && PartOpt[1] && PartOpt[2])
{
query = query.Where(p => (p.PartNumAlt.Contains(partSearchRec.inventory.PartNum)
|| p.PartNumAlt2.Contains(partSearchRec.inventory.PartNum)));
}
// X 0 0
if (PartOpt[0] && !PartOpt[1] && !PartOpt[2])
{
query = query.Where(p => (p.PartNum.Contains(partSearchRec.inventory.PartNum)));
}
. . .
This goes on for a while and seems to be prone to coding errors. In each case we are looking for the same information in any of the selected fields. If I was doing this in SQL I could simply build up the WHERE clause as needed.
Once again I rubber ducked my way to an answer. Rather than throw the question away, here is what I came up with. Is it efficient?
if (partSearchRec.optPartNum || partSearchRec.optAltPartNum1 || partSearchRec.optAltPartNum2)
{
query = query.Where(p => (
(partSearchRec.optPartNum && p.PartNum.Contains(partSearchRec.inventory.PartNum))
|| (partSearchRec.optAltPartNum1 && p.PartNumAlt.Contains(partSearchRec.inventory.PartNum))
|| (partSearchRec.optAltPartNum2 && p.PartNumAlt2.Contains(partSearchRec.inventory.PartNum))));
}
Basically if any of the check boxes are set we will execute the query. Each line of the query will be processed only if the check box was checked. If the left side of an AND is false it doesn't process the right.
This is an aera that Delphi's with statement would be handy. I also learned that you can't use an array inside the LINQ statement.
Given a certain sequence A stored in an array, I have to find if a larger sequence B contains sequence A.
I am stuck at the index part... and i'm getting an error that argument "TGACCA" isn't numeric in array element in line 69 which is:
if (index($record_r1[1], $r2_seq[$check]) != -1)
The code is:
foreach my $check (#r2_seq)
{
if (index($record_r1[1], $r2_seq[$check]) != -1)
{
$matches= $matches + 1;
print "Matched";
}
else
{
}
}
foreach my $check (#r2_seq)
$check takes on the value of each element in #r2_seq. It is not the index.
$r2_seq[$check]
This is attempting to use an element of #r2_seq as the index into #r2_seq. It is unlikely what you want. More probably, you want to use
$check
as in
if (index($record_r1[1], $check) != -1)
.
I believe you wanted $check to be index, so then use the following code:
foreach my $index (0..$#r2_seq)
{
if (index($record_r1[1], $r2_seq[$index]) != -1)
{
$matches= $matches + 1;
print "Matched";
}
else
{
}
}
I have a subroutine that will return two hashes when all goes well. But the sub checkouts output of command and if it matches a certain pattern, it returns with "-1". Is there anyway to check the return of the subroutine from where I called it?
Kinda like:
if (RETURN_VALUE == -1){
do something}
else
go as normal with the hashes
How could one function return two hashes?
If you mean hashrefs, the check would be quite simple:
my ($h1,$h2) = myFunction();
if ( !ref($h1) || (ref($h1) ne "HASH"))
{
die 'error';
}
You function should return references to the two hashes on success and nothing upon failure. Then you can just check the truth value of the function call.
sub myfunc {
my %hash1;
my %hash2;
return (\%hash1, \%hash2);
}
my $ref1;
my $ref2;
unless (($ref1, $ref2) = myfunc()) {
print "Something went wrong\n";
} else {
print "OK\n";
}
If you return two (or any number for that matter) hashes from a subroutine, the result will be a single hash. You will not be able to separate the original hashes from the result in a normal manner. Returning hash references will not exhibit this problem.
Suppose foo() returns two hash references when the pattern is matched and returns -1 when it does not match.
my ( $value_1, $value_2 ) = foo;
if ( $value_1 == -1 ) {
# pattern did not match
}
else { # for strict checks: elsif ( ref $value_1 eq 'HASH' && ref $value_2 eq 'HASH' ) {
# pattern matched
}