http://www.perlmonks.org?node_id=1038338


in reply to why use a hash instead of an array

Hi DarrenSol
Wonderful answers has been given, but maybe this little example / question could also "say" something.
If I give the following:

teacher students professor students school class teacher desk table chalk borad class school teacher
And I ask that for these:
1. print out all the words, without repeating any, 2. print out all the repeated words only, 3. print out the number of times each words is seen and probably an illustration this with an histogram.
How would you do these.

Let me answer QnS 1. and 2., allow you to figure question 3 and try your hands on other solution WITHOUT USING HASH
use strict; use warnings; my %hash; while(<DATA>){ chomp; $hash{$_}++ for split; } print join $/ => sort keys %hash; print $/,$/, join $/ => grep {$_ if $hash{$_} > 1} sort keys %hash; __DATA__ teacher students professor students school class teacher desk table chalk borad class school teacher
Solution:
  1. borad chalk class desk professor school students table teacher
  2. class school students teacher
That brings me to a statement I read in Programming Perl a while a go that 'Until you start thinking in terms of hashes, you aren’t really thinking in Perl.'

If you tell me, I'll forget.
If you show me, I'll remember.
if you involve me, I'll understand.
--- Author unknown to me

Replies are listed 'Best First'.
Re^2: why use a hash instead of an array
by 5mi11er (Deacon) on Jun 11, 2013 at 21:18 UTC
    For a person just learning perl, your example code is quite obtuse. You should at least attempt to explain how your code actually works.

    I'd do it for you, but need to leave work now...

    Update: since no one else has yet done so, and I'm back at work now, I'll try:

    So, the $/ floating all over the above post is simply a special variable holding, by default, a "new line" character, ie. "\n". The first section

    while(<DATA>){ chomp; $hash{$_}++ for split; }
    simply reads in the data, and for every word in the DATA section, increments the hash table entry for that word. It would be more clear to beginners if it were written thusly:
    while(<DATA>){ #get a line of text from the DATA area, put it in spec +ial variable $_ chomp; #remove the "new line" character from the $_ variable #create a word array from the $_ variable #split with no options splits on whitespace by default @words = split; foreach $word (@words) { $hash{$word}++; #increment the value pointed to by the $hash{ +$word} "key" } }
    Once you have the data read in, you'll have the following data structure:
    board => 1 chalk => 1 class => 2 desk => 1 professor => 1 school => 2 students => 2 table => 1 teacher => 3
    2teez then uses more advanced perl to essentially do the following:
    foreach $word (sort keys %hash) { print "$word\n"; } print "\n"; foreach $word (sort keys %hash) { if ($hash{$word} > 1) { print "$word\n"; } }
    From these two beginner friendly examples, it should be pretty easy to do 2teez's 3rd challenge which is to print out the data structure I gave above.

    -Scott

Re^2: why use a hash instead of an array
by Lotus1 (Vicar) on Jun 12, 2013 at 19:04 UTC
    grep {$_ if $hash{$_} > 1} sort keys %hash

    The '$_ if' is redundant since that is what grep does by default, return $_ if the clause is true. The following works the same way:

    grep { $hash{$_} > 1 } sort keys %hash
      actually not quite =)

      grep { $hash{$_} > 1 } is equivalent to map {$_ if $hash{$_} > 1}

      grep {$_ if $hash{$_} > 1} only greps if the key $_ is also true.

      Which I agree is very odd code!

      Cheers Rolf

      ( addicted to the Perl Programming Language)

        It looks like we were both wrong. None of them are equivalent. ;)

        use strict; use warnings; use Data::Dumper; my %hash; while(<DATA>){ #chomp; $hash{$_}++ for split; } $hash{''}=2; print Dumper(\%hash); print '*'x55,"\n"; my @greparr= grep {$hash{$_} > 1} sort keys %hash; print "greparr has ", scalar @greparr, " elements.\n"; my @maparr = map {$_ if $hash{$_} > 1} sort keys %hash; print "maparr has ", scalar @maparr, " elements.\n"; my @grep2 = grep {$_ if $hash{$_} > 1} sort keys %hash; print "grep2 has ", scalar @grep2, " elements.\n"; print '*'x55,"\n"; print Dumper(\@greparr); print '*'x55,"\n"; print Dumper(\@maparr); print '*'x55,"\n"; print Dumper(\@grep2); print '*'x55,"\n"; __DATA__ 0 0 teacher students teacher students nope

        Output:

        $VAR1 = { '' => 2, '0' => 2, 'nope' => 1, 'students' => 2, 'teacher' => 2 }; ******************************************************* greparr has 4 elements. maparr has 5 elements. grep2 has 2 elements. ******************************************************* $VAR1 = [ '', '0', 'students', 'teacher' ]; ******************************************************* $VAR1 = [ '', '0', '', 'students', 'teacher' ]; ******************************************************* $VAR1 = [ 'students', 'teacher' ]; *******************************************************