import-bot (20211) [Avatar] Offline
#1
[Originally posted by dru145]

Hi Andrew,

I have seen this questions about this following statement in other posts:

next if $seen{$value}++;

It is still not clicking for me. Hashes have been the hardest thing for me to
grasp (I guess other programming newbies as well).

I can't figure out how this is matching a value you have already entered and
cause the rest of the loop to be skipped and start all over again (this is
what the next statement does correct?)

Also, how is the $seen{$value} holding the number of times a certain value was
entered?

Say I enter the value cat. This will be assigned to the variable $value, then
to the array @value. Now if I enter the value cat again is it getting assigned
as a key in the %seen hash? What will it's value be in the hash?

Thanks,
Dru
import-bot (20211) [Avatar] Offline
#2
Re: Exercise 5.6.2
[Originally posted by jandrew]

> Hi Andrew,
>
> I have seen this questions about this following statement in other
> posts:
>
> next if $seen{$value}++;
>
> It is still not clicking for me. Hashes have been the hardest thing
> for me to grasp (I guess other programming newbies as well).

Hashes certainly do not always seem obvious to beginners, and
different explanations make it click for different people. For some,
a dictionary-like explanation works ... think of a hash as somewhat
similar to a dictionary: a 'key' is simply a word-entry in the
dictionary, and the 'value' is the definition for that word. If you
add a new word (that isn't in the dictionary) you create a new slot
for it and place its definition with it. However, if you have a word
with two definitions you don't create two entries, you have one entry
and you add the second definition to the first (at least generally
speaking).

But let's take a different approach. Consider an ordinary array:

@array = (42,13,3);

Now, think of an array as simply an ordered set of slots and each
slot is 'named' with its number in the sequence (starting with zero).
So, for the above array we have:

array name slot name value
array 0 42
array 1 13
array 2 3

You can never have two slots with the same name, so if we do:

$array[1] = 21;

We have not added a new number 1 slot, we have simply reset the value
in that slot to 21 --- (our array now holds: (42, 21, 3)). Now, what
if we increment that value rather than replace it:

$array[1]++; # same as: $array[1] = $array[1] + 1;

Now the value in that slot is 22. The thing about arrays is that
slots are always named with numbers, and we don't have to provide
those names when doing a list assignment like:

@array = (42, 13, 3);

because the inherent ordering *is* the slot ordering (so we don't
really think about them as being named, and we simply talk about
array indices).

OK, now for the linkage to hashes: A hash is rather like an array
except that the slots are not ordered and do not automatically have
names --- we get to (have to, actually) name a slot with any string
we want (the key) and then store a value in it. So, we can have a
hash:

%hash = (0 => 42, 1 => 13, 2 => 3);

So we have named the slots '0', '1', and '2' --- ie, used the same
names that the array gave us automatically. But, we could use any
slot name we want:

%pets = (cat => 42, dog => 13, goldfish => 3);

and our structure is:

hash name slot name value
pets cat 42
pets dog 13
pets goldfish 3

And, if then do:

$pets{cat}++; # increments the value for slot 'cat'

All we've done is increment the value already stored in that
slot name (to 43).

So, let's look at getting the unique values from a small list
in a slightly expanded form:

my @list = ('cat', 'dog', 'cat', 'cat', 'fish', 'dog');
my @uniq;
my %seen;
foreach my $word (@list) {
$seen{$word} += 1;
next if $seen{$word} > 1;
push @uniq, $word;
}
print "@uniq
";

OK, so we loop over each 'word' in the @list. On the first line in
the loop we add 1 to the value of $seen{$word} (if it didn't yet
exist, perl creates that slot and treats its undefined value as zero,
so adding 1 makes it 1). The second line skips the rest of the loop
if that slot's value is greater than 1 (it isn't the first time we
see 'cat', but it will be each time we see 'cat' again). If we get to
the third line, this is the first occurrence of that $word so we push
it onto the @ unique list.

This isn't exactly the same is the solution file's version, and
perhaps it is the quirky way the ++ operator works that has thrown
you off guard (my fault for not really describing it in detail in
the book). Anyway, here is how it works: If I say $a++, perl first
gets the value of $a and uses it in whatever expression it occurs
in, and then perl increments $a's value. So,

my $a = 0;
my $b = $a++;
print "$a $b
"; #prints: 1 0

In the second line, the value of $a is obtained (zero) and assigned
to $b, *then* $a is incremented by one. So, we can change the above
to the more simple:


my @list = ('cat', 'dog', 'cat', 'cat', 'fish', 'dog');
my @uniq;
my %seen;
foreach my $word (@list) {
next if $seen{$word}++;
push @uniq, $word;
}
print "@uniq
";

Now the first line of the loop tests $seen{$word}++ ... if that slot
(say 'cat') doesn't yet exist then that is a false value so the if
test fails and the next will be executed (but, after we tested
$seen{$word} it is then incremented (becomes 1 which will be true the
next time 'cat' is the current word). Thus, the slot 'cat' will be
incremented by one each time 'cat' is the current $word, but the if
test will only fail the very first time (before the slot has any
value) ... after that the slot 'cat' has a true value.

Just for completeness, there is also ++$a, which first increments $a
and *then* uses it:

my $a = 0;
my $b = ++$a;
print "$a $b"; #prints: 1 1

In this case the ++ appears before the variable (called prefix
increment as opposed to postfix increment $a++), so the increment is
done first and then the resulting value of $a is assigned to $b.

I hope this clarifies hashes and the ++ operator to some extent. If
anything still doesn't make sense let me know and we'll try to find
the explanation that *does* make it click for you.

regards,
andrew
import-bot (20211) [Avatar] Offline
#3
Re: Exercise 5.6.2
[Originally posted by dru145]

Andrew,

Thanks, after reading this reply and one you offered in a previous post, it
has finally clicked.

I know this has been said before, but I feel that your book is a godsend to us
non-programmers. I tried to read Learning Perl and even Perl for Dummies (even
though I will deny it until the day I die : ) and neither of them can hold a
candle to this book.

One more question, how come you don't offer www.perlmonks.org as a reference
for help? I can't think of a better place for a Perl programmer at any level
to get help. I'm guessing it is due to restrictions your publisher has put on
you.

Thanks Again,
Dru
import-bot (20211) [Avatar] Offline
#4
PerlMonks a good resource.
[Originally posted by jandrew]

Dru,

> Thanks, after reading this reply and one you offered in a previous
> post, it has finally clicked.

Ahh, that's good.

> I know this has been said before, but I feel that your book is a
> godsend to us non-programmers. I tried to read Learning Perl and even
> Perl for Dummies (even though I will deny it until the day I die : )
> and neither of them can hold a candle to this book.

Thanks ... and I won't tell anyone about the Dummies book.

> One more question, how come you don't offer www.perlmonks.org as a
> reference for help? I can't think of a better place for a Perl
> programmer at any level to get help. I'm guessing it is due to
> restrictions your publisher has put on you.

No restrictions from the publisher at all. PerlMonks only just came
into existence at around the same time as my book came out (fall
1999). Though I had noticed the site by the time the second printing
came out, I didn't think it had been around long enough to be sure it
wouldn't fizzle out. I didn't even sign on there myself until Jan
2001 (I am 'danger' on perlmonks). But I do agree with you that
www.perlmonks.org is an excellent resource for Perl programmers of
any level (thanks for bringing that up).

regards,
andrew