in reply to Counting incidents of names in a file

The solution of the Unnamed One is correct but a little terse if you are still learning. Here's a more spelled-out version of the same general idea:
#!/usr/bin/perl -w use strict; my %hash; # Do it for (<DATA>) { my ($name, $score, $date) = split /\|/; $hash{$name}++; } #Show it for (keys %hash) { print "$_ = $hash{$_}\n"; } __DATA__ name_x|score|date name_y|score|date name_z|score|date name_x|score|date name_z|score|date name_z|score|date
And just to explain what is happening with AM's solution: $name{(split/\|/)[0]} += 1; (split/\|/) returns a list which is then subscripted to get the zeroth element which is then used as the key for the %name hash. The value associated with that key (which may be magically created if it didn't exist before) is increased by one using the += assignment operator.

Just a word of encouragement about hashes. They are a wonderful tool for many purposes. And it is commonly said that you are not really programming in Perl until you can think in terms of hashes. Your point about their lacking a fixed order is well taken, but once you begin using hashes, you may be pleasantly surprised to discover how often that doesn't matter.

Replies are listed 'Best First'.
Re: Re: Counting incidents of names in a file
by Bishma (Beadle) on Feb 13, 2002 at 06:34 UTC
    Ok, the hash makes sense. Thanks for you help. Now (since I know next to nothing about hashes and I don't have my books) I need to ask another question. I kept my question simple for ease of understanding, but now I need to get more indepth.

    My data set also contain a "class" element like so:
    name_x|score|date|class1 name_y|score|date|class2 name_y|score|date|class2 name_a|score|date|class2 name_b|score|date|class3 name_z|score|date|class1 name_b|score|date|class3 name_x|score|date|class1 name_b|score|date|class3 name_c|score|date|class2 name_c|score|date|class3 name_c|score|date|class3 ...and so on
    I need 3 seperate lists (actually html tables) based on the class (3 possible classes) and I need the lists in decending order by number of incidents of the names. so we get:
    _class1_ name_x = 2 name_z = 1 _class2_ name_y = 2 name_c = 1 _class3_ name_b = 3 name_c = 2
    I know this is getting a little complex, but I'm lost.
    Thanks again.
      This looks like feature creep to me, or should we say, wanting others to do all the work. Please post some code to show that you have attempted to solve this problem on your own. The other monks it appears were very generous with your first question, but coming back with no attempt to solve on your own is not a good idea. That said I am sure someone will post a solution because most of us just can't help ourselves. :)
      Simply modify my last code to include the classes.
      use strict; use Data::Dumper; my @all; my %occurances; while (<DATA>) { chomp $_; push @all, [ split(/\|/,$_) ]; # I should explain what is going on here # the -1 is going to get the last element # in a list. In this case the first [-1] # is the last list of elements added # from the DATA section below with the push # function. The second -1 # is the last element of that list which # is the class. The next key in the # occurances hash is the name_? value # which is extracted from the last array # (-1) pushed onto the @all and the first # element (0) of the annoymous array in # in that (-1) location of @all. $occurances{$all[-1][-1]}{$all[-1][0]}++; # class # name_? } print Dumper(\@all); print Dumper(\%occurances); __DATA__ name_x|score|date|class1 name_y|score|date|class2 name_y|score|date|class2 name_a|score|date|class2 name_b|score|date|class3 name_z|score|date|class1 name_b|score|date|class3 name_x|score|date|class1 name_b|score|date|class3 name_c|score|date|class2 name_c|score|date|class3 name_c|score|date|class3