Please explain me what is hapenning in line 3 of this code - perl

Please explain me what is hapenning in line 3 of this code.
for my $i (0 .. $dim) {
for my $j (0 .. $dim) {
$adj->[$i][$j] = $adj->[$i][$j] ? [$j] : [];

The code loops over two dimensions in an array reference $adj. Presumably, $dim is the dimension, and $i and $j iterate over a list of numbers from 0 to $dim, e.g. 0,1,2,3,4,5.
For each combination of numbers, the value of that array element is checked for trueness, and is assigned a new value. If the value is false, it is assigned an array ref containing the index $j, otherwise an empty array ref [].
The conditional operator is used here, with the basic syntax
CONDITION ? FOO : BAR
if CONDITION then FOO else BAR
Presumably, the array ref $adj is supposed to contain array references, which is why it can simply check for trueness as a shortcut for defined $adj->[$i][$j].

This is the ternary operator, aka conditional operator.
If $adj->[$i][$j] is 0 (or undefined) then [] is assigned to $adj->[$i][$j], in the other cases $adj->[$i][$j] is assigened to $adj->[$i][$j].
perlop has this quote:
Ternary "?:" is the conditional operator, just as in C. It works much like an if-then-else.
If the argument before the ? is true, the argument before the : is returned, otherwise the argument after the : is returned.

for my $i (0 .. $dim) {
for my $j (0 .. $dim) {
Above for loops will itrate through the arry with dimension $dim x $dim
$adj->[$i][$j] = $adj->[$i][$j] ? [$j] : [];
if $adj->[$i][$j] is zero, then assign [] to $adj->[$i][$j] else assign $j (column value)

Related

Sort command in Perl - Can someone explain what is happening in this script?

new coder here working in Perl. Can someone explain to me what the following portion of the below code is doing? I know that it is performing an alphabetical sort of the elements in array #animals and I think it is then assigning the sorted index values to #idx. I have no idea what the last portion "0 .. $#animals;" is doing. It appears that '..' is the range operator in Perl.
my #idx = sort {
$animals[$a] cmp $animals[$b]
} 0 .. $#animals;
Here is the full code:
#animals = (dog,cat,iguana,parakeet,monkey, giraffe);
#diets = (beef,chicken,chickpeas,seeds,bananna,tree);
#age = (7,3,5,2,20,18);
my #idx = sort {
$animals[$a] cmp $animals[$b]
} 0 .. $#animals;
#animals = #animals[#idx];
#diets = #diets[#idx];
#age = #age[#idx];
print "#animals\n";
print "#diets\n";
print "#age\n";
$#animals is the index of the last entry in #animals; in your example, that'd be 5.
The range operator takes that 0 .. 5 and expands it to 0, 1, 2, 3, 4, 5.
That list of integers gets passed to sort, which treats them as indexes into #animals and sorts them based on the value in that array.
Incidentally, parallel arrays make a great candidate for some other structure, like an array of hash references.

What this mean !$var PERL?

I get some code It works but don't understan this part !$dump_done...
my $dump_done = 0;
foreach my $line(keys %results){
if ($results{$line} == 1 and !$dump_done) {
print Dump($post);
$dump_done = 1;
}
}
! is the Logical NOT operator. It will return the negation of $dump_done. If $dump_done contains 0, the negation will give you 1:
my $dump_done = 0;
print !$dump_done; # Prints 1
This is valid, because in Perl any non-zero value is considered true and 0 is considered false.
You can try out this snippet:
if (5) {
print "Hello"; # Will be executed.
}
The ! character in most programming languages stands for NOT, it's the negation.
If the value of your variable $dump_done is still zero, when you test $dump_done it will returns FALSE (0). If you negate this expression, you get a TRUE expression (!= 0).
See Truth and Falsehood

What do Perl functions that return Boolean actually return

The Perl defined function (and many others) returns "a Boolean value".
Given Perl doesn't actually have a Boolean type (and uses values like 1 for true, and 0 or undef for false) does the Perl language specify exactly what is returned for a Boolean values? For example, would defined(undef) return 0 or undef, and is it subject to change?
In almost all cases (i.e. unless there's a reason to do otherwise), Perl returns one of two statically allocated scalars: &PL_sv_yes (for true) and &PL_sv_no (for false). This is them in detail:
>perl -MDevel::Peek -e"Dump 1==1"
SV = PVNV(0x749be4) at 0x3180b8
REFCNT = 2147483644
FLAGS = (PADTMP,IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK)
IV = 1
NV = 1
PV = 0x742dfc "1"\0
CUR = 1
LEN = 12
>perl -MDevel::Peek -e"Dump 1==0"
SV = PVNV(0x7e9bcc) at 0x4980a8
REFCNT = 2147483647
FLAGS = (PADTMP,IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK)
IV = 0
NV = 0
PV = 0x7e3f0c ""\0
CUR = 0
LEN = 12
yes is a triple var (IOK, NOK and POK). It contains a signed integer (IV) equal to 1, a floating point number (NV) equal to 1, and a string (PV) equal to 1.
no is also a triple var (IOK, NOK and POK). It contains a signed integer (IV) equal to 0, a floating point number (NV) equal to 0, and an empty string (PV). This means it stringifies to the empty string, and it numifies to 0. It is neither equivalent to an empty string
>perl -wE"say 0+(1==0);"
0
>perl -wE"say 0+'';"
Argument "" isn't numeric in addition (+) at -e line 1.
0
nor to 0
>perl -wE"say ''.(1==0);"
>perl -wE"say ''.0;"
0
There's no guarantee that this will always remain the case. And there's no reason to rely on this. If you need specific values, you can use something like
my $formatted = $result ? '1' : '0';
They return a special false value that is "" in string context but 0 in numeric context (without a non-numeric warning). The true value isn't so special, since it's 1 in either context. defined() does not return undef.
(You can create similar values yourself with e.g. Scalar::Util::dualvar(0,"").)
Since that's the official man page I'd say that its exact return value is not specified. If the Perl documentation talks about a Boolean value then then it almost always talks about evaluating said value in a Boolean context: if (defined ...) or print while <> etc. In such contexts several values evaluate to a false: 0, undef, "" (empty strings), even strings equalling "0".
All other values evaluate to true in a Boolean context, including the infamous example "0 but true".
As the documentation is that vague I would not ever rely on defined() returning any specific value for the undefined case. However, you'll always be OK if you simply use defined() in a Boolean context without comparing it to a specific value.
OK: print "yes\n" if defined($var)
Not portable/future proof: print "yes\n" if defined($var) eq '' or something similar
It probably won't ever change, but perl does not specify the exact boolean value that defined(...) returns.
When using Boolean values good code should not depend on the actual value used for true and false.
Example:
# not so great code:
my $bool = 0; #
...
if (some condition) {
$bool = 1;
}
if ($bool == 1) { ... }
# better code:
my $bool; # default value is undef which is false
$bool = some condition;
if ($bool) { ... }
99.9% of the time there is no reason to care about the value used for the boolean.
That said, there are some cases when it is better to use an explicit 0 or 1 instead of the boolean-ness of a value. Example:
sub foo {
my $object = shift;
...
my $bool = $object;
...
return $bool;
}
the intent being that foo() is called with either a reference or undef and should return false if $object is not defined. The problem is that if $object is defined foo() will return the object itself and thus create another reference to the object, and this may interfere with its garbage collection. So here it would be better to use an explicit boolean value here, i.e.:
my $bool = $object ? 1 : 0;
So be careful about using a reference itself to represent its truthiness (i.e. its defined-ness) because of the potential for creating unwanted references to the reference.

Perl - how do I get the previous key in a hash?

I have a hash that has been filled with an unknown number of keys that are strings. Each key's value is zero to start.
I want to iterate through this hash and for each element except the first, make its value equal the equivalent in another hash I have plus the previous value in this hash. So mathematically something like:
hash1:a = hash2:a;
hash1:b = hash2:b + hash1:a;
hash1:c = hash2:c + hash1:b;
hash1:d = hash2:d + hash1:c;
hash1:e = hash2:e + hash1:d;
...
I'm not even really sure I know how to do the first one as I don't know what the value or key is. I plan to sort it first, but as the keys could be any in a list I have I cannot specify what would be first exactly. I don't know how to reference the previous value based on the key. Is this possible?
(I don't have any code to show I'm afraid, I tried but I just realised that it is very wrong haha)
Hashes themselves are unordered, so they have no idea of a 'previous' key. You'd need to extract the keys using the keys function, sort them (as you said) and then refer to the previous element of the list of keys to find out what the previous key in your chosen order was.
Once you have that previous key, you can then access the value from the hash using the usual $hash{$key} syntax.
The trick then becomes accessing the previous key in the list, which probably entails iterating over the list by index, as a foreach loop doesn't give you any idea where in the list you currently are. Something like
for (my $i = 0; $i <= $#keys; ++$i) {
if ($i == 0) { ... } # first key
else { ... } # all other keys
}
might be appropriate.
This is basically a cumulative sum over all hash values:
a’ = (0) + a
b’ = (0 + a) + b
c’ = (0 + a + b) + c
d’ = 0 + ...
Iterating over the hash, storing the sum and always adding the current value (or adding the sum to the current value, doesn't matter, addition is commutative) should get you the desired result.
Note that you must sort your keys first, because hashes are unordered by definition.
$sum = 0;
foreach my $k (sort keys %hash) {
$hash{$k} += $sum;
}
The resulting hash will not be sorted either, so you have two options:
Every time you work with the hash (iterate over it) you have to iterate over the sorted keys and then access the hash at that key position. Just use the loop I have given above and swap its body with whatever you want.
Store your sums in a list/array. These data structures don't change their order of values (but you won't have key value pairs; only values).

Secondary Order in Heap::Simple

How do I define a secondary ordering to the Heap::Simple interface in Perl?
The documentation states that the constructor takes a code reference to define
the order, so you can specify any sort method you like:
my $heap = Heap::Simple->new(order => \&sort_method);
Every time two keys need to be compared, the given code reference will be called like:
$less = $code_reference->($key1, $key2);
This should return a true value if $key1 is smaller than $key2 and a false
value otherwise. $code_reference should imply a total order relation, so it
needs to be transitive.
By "secondary ordering" I assume you mean that a second comparison is used if
the first one shows the values to be equal. Let's say the first comparison is
of values found via the "method1" method, and the second comparison is of
values from "method2". So, if by method1 the values are different, return
that result, and otherwise fall back to method2:
sub sort_method
{
my ($val1, $val2) = #_;
my $result = ($val1->method1 <=> $val2->method1)
||
($val1->method2 <=> $val2->method2);
return 1 if $result == -1;
}
If method1 and method2 return strings instead of numeric values, simply use
the cmp operator instead of <=>. You can use anything you like, as long
as the operator returns the right values. Most sort functions like using the
values -1, 0 and 1 to indicate whether value1 is less than, equal to, or
greater than value2, but this module likes 1 to mean val1 < val2, so after
gathering the -1, 0, 1 result, one then returns 1 if the result is -1 (where
value1 is less than value2).
First of all, you write a function that takes two of the objects you want to put in the heap, and returns a true value if the first one is smaller than the second, and false otherwise.
Then supply that as a coderef to Heap::Simple.
The example from the Heap::Simple docs is as follows:
use Heap::Simple;
sub more { return $_[0] > $_[1] }
my $heap = Heap::Simple->new(order => \&more);
$heap->insert(8, 3, 14, -1, 3);
print $heap->extract_top, " " for 1..$heap->count;
print "\n";
# Will print: 14 8 3 3 -1