Reputation: 313
An easy one for a Perl guru...
I want a function that simply takes in an array of items (actually multiple arrays) and counts the number of times each item in the key section of a hash is there. However, I am really unsure of Perl hashes.
@array = qw/banana apple orange apple orange apple pear/
I read that you need to do arrays using code like this:
my %hash = (
'banana' => 0,
'orange' => 0,
'apple' => 0
#I intentionally left out pear... I only want the values in the array...
);
However, I am struggling getting a loop to work that can go through and add one to the value with a corresponding key equal to a value in the array for each item in the array.
foreach $fruit (@array) {
if ($_ #is equal to a key in the hash) {
#Add one to the corresponding value
}
}
This has a few basic functions all wrapped up in one, so on behalf of all beginning Perl programmers, thank you in advance!
Upvotes: 1
Views: 205
Reputation: 319
This will be easier to understand as I too started to write code just 2 months back.
use Data::Dumper;
use strict;
use warnings;
my @array = qw/banana apple orange apple orange apple pear/;
my %hashvar;
foreach my $element (@array) {
#Check whether the element is already added into hash ; if yes increment; else add.
if (defined $hashvar{$element}) {
$hashvar{$element}++;
}
else {
$hashvar{$element} = 1;
}
}
print Dumper(\%hashvar);
Will print out the output as $VAR1 = { 'banana' => 1, 'apple' => 3, 'orange' => 2, 'pear' => 1 }; Cheers
Upvotes: 1
Reputation: 107090
I'm trying to understand you here:
Think of hashes as keyed arrays. Arrays have a position. You can talk about the 0th element, or the 5th element. There is only one 0th element and their is only one 5th element.
Let's look at a hash:
my %jobs;
$jobs{bob} = "banker";
$jobs{sue} = "banker";
$jobs{joe} = "plumber;
Just as we can talk about the element in the array in the 0th position, we can talk about the element with the of bob
. Just as there is only one element in the 0th position, there can only be one element with a key of bob
.
Hashes provide a quick way to look up information. For example, I can quickly find out Sue's job:
print "Sue is a $jobs{sue}\n";
We have:
Here's the code:
use strict;
use warnings;
use feature qw(say);
my @items = qw(.....); # Items we want to count
my %valid_items = (....); # The valid items we want
# Initializing the totals. Explained below...
my %totals;
map { $totals{$_} = 0; } keys %valid_items;
for my $item ( @items ) {
if ( exists $valid_items{$item} ) {
$totals{$item} += 1; #Add one to the total number of items
}
}
#
# Now print the totals
#
for my $item ( sort keys %totals ) {
printf "%-10.10s %4d\n", $item, $totals{$item};
}
The map command takes the list of items on the right side (in our case keys %valid_items
), and loop through the entire list.
Thus:
map { $totals{$_} = 0; } keys %valid_items;
Is a short way of saying:
for ( keys %valid_items ) { $totals{$_} = 0; }
The other things I use are keys which returns as an array (okay list) all of the keys of my hash. Thus, I get back apple
, banana
, and oranges
when I say keys %valid_items
.
The [exists](http://perldoc.perl.org/functions/exists.html) is a test to see if a particular key is in my hash. The value of that key might be zero, a null string, or even an undefined value, but if the key is in my hash, the
exists` function will return a true value.
However, if we can use exists
to see if a key is in my %valid_items
hash, we could do the same with %totals
. They have the same set of keys.
Instead or creating a %valid_items
hash, I'm going to use a @valid_items
array because arrays are easier to initialize than hashes. I just have to list the values. Instead of using keys %valid_items
to get a list of the keys, I can use @valid_items
:
use strict;
use warnings;
use feature qw(say);
my @items = qw(banana apple orange apple orange apple pear); # Items we want to count
my @valid_items = qw(banana apple orange); # The valid items we want
my %totals;
map { $totals{$_} = 0; } @valid_items;
# Now %totals is storing our totals and is the list of valid items
for my $item ( @items ) {
if ( exists $totals{$item} ) {
$totals{$item} += 1; #Add one to the total number of items
}
}
#
# Now print the totals
#
for my $item ( sort keys %totals ) {
printf "%-10.10s %4d\n", $item, $totals{$item};
}
And this prints out:
apple 3
banana 1
orange 2
I like using printf for keeping tables nice and orderly.
Upvotes: 1
Reputation: 11452
Suppose you have an array named @array
. You'd access the 0th element of the array with $array[0]
.
Hashes are similar. %hash
's banana element can be accessed with $hash{'banana'}
.
Here's a pretty simple example. It makes use of the implicit variable $_
and a little bit of string interpolation:
use strict;
my @array = qw/banana apple orange apple orange apple pear/;
my %hash;
$hash{$_} += 1 for @array; #add one for each fruit in the list
print "$_: $hash{$_}\n" for keys %hash; #print our results
If needed, you can check if a particular hash key exists: if (exists $hash{'banana'}) {...}
.
You'll eventually get to see something called a "hashref", which is not a hash but a reference to a hash. In that case, $hashref
has $hashref->{'banana'}
.
Upvotes: 1
Reputation: 126772
All you need is
my @array = qw/banana apple orange apple orange apple pear/;
my %counts;
++$counts{$_} for @array;
This results in a hash like
my %counts = ( apple => 3, banana => 1, orange => 2, pear => 1 )
The for
loop can be written with block and a an explicit loop counter variable if you prefer, like this
for my $word (@array) {
++$counts{$word};
}
with exactly the same effect.
Upvotes: 6
Reputation: 1921
You can use exists
.
http://perldoc.perl.org/functions/exists.html
Given an expression that specifies an element of a hash, returns true if the specified element in the hash has ever been initialized, even if the corresponding value is undefined.
foreach my $fruit (@array) {
if (exists $hash{$fruit}) {
$hash{$fruit}++;
}
}
Upvotes: 1