Joe,

Thank you for taking the time to explain this bit of code.  I have spent
some time trying to understand the ternary operator (?:) this evening and I
think it is making more sense.  In the past I have seen this operator and
moved on in favor of using if/then/else statements but I can see how in this
example it is much simpler to evaluate the EXPR with a ternary than to use
code blocks.  I can now see mostly how this expression works in your
example.  I see that the first expression says $actual{$_} equal
$register{$_} if this is true then $_ equals the hostname.  But, if this
statement is false then I see that we dereference the $_ values in both
Arrays. 

When I do run this code though it seems to print out the memory address for
the hostname reference which I think means it is not being dereferenced
correctly but I don't see how it differs form the else part of the print
statement

ARRAY(0x816e00c) differs:actual 164.72.119.175 <-> register 164.72.119.179
ARRAY(0x816e03c) differs:actual 164.72.123.43 <-> register 164.72.21.43
host3 is ok
ARRAY(0x819bed4) differs:actual 164.72.98.89 <-> register 164.72.8.89
host5 is ok

I still have some ways to go with really understanding this but I am closer.


Well again thanks for your help,

-angus

P.s. Your English is probably better than mine; I wouldn't know it wasn't
your first language if you didn't mention it.


-----Original Message-----
From: John Doe [mailto:[EMAIL PROTECTED] 
Sent: Thursday, February 02, 2006 3:26 AM
To: beginners@perl.org
Subject: Re: How to compare hashes to find matching keys with conflicting
values.

Angus am Donnerstag, 2. Februar 2006 10.14:
> John,

Hello Angus

> Well that works perfect now my issue is to understand what you have
> provided for me.  I see that we are creating an array called res however I
> am not sure what map is doing.  I did read the perldoc info on map but I
am
> still confused on how it is being used here.  I see from the perldoc that
I
> could use it like this
>
> %register = map {$register($) => $_ @array;
> print "@array\n";

No, this is syntactically incorrect and wouldn't do anything useful.

> This would I think create an array based on the values contained in the
> register hash.  

No; in an assignement

 <anything> = <anything_else>

the left part is made from the expression on the right.

> But, I would have now way to link them back to the keys
> from register as now they would be numerically ordered in the array
instead
> of being linked to the hostname key.
>
> So I am looking at your example:
> %actual = map ($actual{$_} eq $register{$_})

This is not my example... and syntactically incorrect.

> This I think says each key eq to the other key value.  

The part within the braces does a comparison between $actual{$_} and 
$register{$_}. Result is true or false.


> Next you use a ? mark which I understand means that the previous 
> values are optional, 

No, its part of the ternary ?: operator (see perldoc perlop).

my $var = $x ? $y : $z

is the same as

my $var;
if ($x) {
  $var=$y;
}
else {
$var=$z;
}

> which  
> in this case if the are not equal are they then not included in the $_
> variable.  But if they are eq then they are included in the $_ value which
> means they are placed back into the hashes?  After this the register hash
> is sorted but I don't understand why.

It's because of the sort (see perldoc -f sort) in the expression. The keys
of 
%keys are sorted with it before it goes through the "map pipe".

> The next code block iterates through the res array and unless it finds a
> reference?  I did a perldoc on ref and see that it returns a non-empty
> string if EXPR is a reference.  So now I think we created an array of
> hashes with the @res and map combo, is that correct?

Ok, let's analyse in detail:

[...]
> my %actual = (
> "host1" => "164.72.119.175",
> "host2" => "164.72.123.43",
> "host3" => "164.72.45.98",
> );
>
> my %register = (
> "host1" => "164.72.119.179",
> "host2" => "164.72.21.43",
> "host3" => "164.72.45.98",
> );
[citation removed, reformatted:]

my @res = map {
   ( $actual{$_} eq $register{$_} )
   ? $_
   : [ $actual{$_}, $register{$_} ]
} sort keys %register;

The whole expression is to read from bottom to top; %register is the start;
it 
is handled in 3 ways each after the other, resulting in @res.

1st, the keys are taken (keys %register).
2nd, the keys are sorted (sort)
3rd, map creates a new structure.

You could image some sort of "pipe" with stations:
entity:@res <- do:map <- do:sort <- do:keys <- entity:%register

Note that @res does nowhere occur on the right side: It's the result;
nothing 
is inside it before the expression on the right side of the '=' is
evaluated.


Now to the map part: ... <-- map { <do something> } <-- ... : 
It takes something at the right, mangles it, and puts it out on the left.
(Note the {}-braces are part of the map; it's one of it's two syntax).

Within map{}, $_ contains the sorted keys of %register; one by one is
mangeld 
by map{}. $_ is a scalar, fed to map on the right, and map returns a scalar 
on the left.

The scalar is either the key ( $_ ) or an arrayref [ ... ], depending of the

result of the comparison, taken from after ? or after : .

What the map does here (for every $_ separate) in words:
"Compare the value from %actual keyed by $_ with the value from %register 
keyed by $_. If they are equal (means: if the IPs are equal), return the key

(means: hostname); otherwise, return the two different values (means: the
two 
different IPs) within an arrayref."


I hope this helps and my english was not too confusing.

Just play around with map to get the feeling. I remember that it is not easy

to understand at the beginning, but if you get the idea, you won't miss it, 
because it allows to do complex actions in a very short way.

joe



[nothing new below]
> foreach my $e(@res) {
> unless(ref($e)) {
> print "$e is ok\n";
> }
> else {
> print "$e differs:actual @{[$e->[0]]} <-> register @{[$e->[1]]}\n";
> }
> }
>
>
> -----Original Message-----
> From: John Doe [mailto:[EMAIL PROTECTED]
> Sent: Wednesday, February 01, 2006 2:45 AM
> To: beginners@perl.org
> Subject: Re: How to compare hashes to find matching keys with conflicting
> values.
>
> Sorry for another mail, but there are too many typos:
> > Also untested:
> >
> > # If no conflict, value is hostname.
> > # If conflict, value is arrayref with the two different IPs
> > #
> > my @res = map {
> >   ($actual{$_} eq $register{$_})
> >   ? $_
> >
> >   : [$actual{$_}, $register{$_}]
> >
> > } sort keys %register;
> >
> > foreach my $e (@res) {
> >   if (ref($e)) {
>
> This should read
>    unless (ref($e)) {
>
> >     print "$e is ok\n";
> >   }
> >   else {
> >     print "$e differs: actual @{[$e->[0]]} <-> register @{[$e->[1]]}\n";
> >   }
> > }
> >
> > I think this should give you an idea.
> > To look op any perl funktion, type:
>
> up, function
>
> > perldoc -f FUNCTIONNAME
> >
> > The man page for operaters:
>
> operators
>
> Nice day to all :-)
>
> --
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
> <http://learn.perl.org/> <http://learn.perl.org/first-response>

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>



-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>


Reply via email to