Hashes are very useful especially in specific list and array tasks. I'll show you some applications. Two of them are most interesting: counting and validating.
@notes = (); $no_elements = 0; sub round { my ($value, $places) = @_; my $factor = 10**$places; return int($value * $factor + 0.5) / $factor; # +0.5 is magical sauce to do rounding instead of truncating } while ($line = <DATA>) { chomp($line); $line =~ s/\h+/ /g; @notes= split(/ /, $line); $no_elements += scalar(@notes); foreach $note(@notes) { $count{$note}++; } } foreach $note (sort keys %count) { $perc = $count{$note} / $no_elements; print($note, " ", $count{$note}, " ", round($perc,2), "\n"); } __DATA__ C E D E F G E A G F E D E G A B C B A G E D C C B C
$grid = [ [1, 2, 3, 4, 5], [1, 2, 3, 2, 3, 4, 5, 6, 4], [4, 5, 6, 4, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 2, 3, 4, 5, 6, 4], [4, 5, 6, 4, 3, 4, 5] ]; %digit_freq = (); foreach $row (@$grid) { foreach (@$row) { # process each digit of the grid $digit_freq{$_}++; } } print "Frequency of each digit:\n"; foreach $digit (sort keys %digit_freq) { print("$digit: $digit_freq{$digit}\n"); }
$grid = [ [1, 2, 3, 4, 5], [1, 2, 3, 2, 3, 4, 5, 6, 4], [4, 5, 6, 4, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 2, 3, 4, 5, 6, 4], [4, 5, 6, 4, 3, 4, 5] ]; %digit_freq = (); foreach $row (@$grid) { foreach ($row) { $digit_freq{$_->[2]}++; # process each digit of the third grid column } } print("Frequency of each digit in the third grid column:\n"); foreach $digit (sort keys %digit_freq) { print("$digit: $digit_freq{$digit}\n"); }
$l_no1 = 1; $h_no1 = 99; $l_no2 = 1000; $h_no2 = 1999; $format = "number whitespace valid_string whitespace number"; # in the hash %valid, all keys are valid alphabetic strings (length 8) with value 1 %valid = ( 'IihiANOS' => 1, 'JMinosXX' => 1, ); sub valid_no { ($no, $lowest, $highest) = @_; ($lowest <= $no <= $highest) ? return 1 : return 0; } print("Test if a input string has the required format: $format\n"); while (<DATA>) { chomp($_);# initial test if the input consists of '1-2 digits whitespace alphabetic_string(length 8) whitespace 1-4 digits' if ($_ =~ /^(\d{1,2})\s{1}([a-zA-Z]{8})\s{1}(\d{1,4})$/) {# the data matched in the first set of parentheses is assigned to the variable $1 etc. $no_1 = $1; $str = $2; $no_2 = $3;# defined(valid{$str}) checks if the string is contained in the hash and thus defined. (valid_no($no_1, $l_no1, $h_no1) and defined($valid{$str}) and valid_no($no_2, $l_no2, $h_no2)) ? print("$_ is valid.\n") : print("$_ is not valid.\n"); } else { print("$_ has not the required format\n"); } } __DATA__ ab 123456 abc 10 eztcUukk 410 9 CaSCvKEo 27 26 IihiANOS 1851 52 JMinosX 612 3 TOCgOwMQ 709
The result is: a b c@abc = qw (a b c);
foreach (@abc) {
print ($_ . " ");
}
The result is 3%abc = (
'a' => '1',
'a' => '1',
'b' => '1',
'b' => '1',
'b' => '1',
'b' => '1',
'c' => '1',
'c' => '1',
'c' => '1'
);
$no_elements = keys (%abc);
print ($no_elements . "\n");
The result is 'Keys of the hash %abc are: a b c'@keys = sort(keys(%abc));
print ("Keys of the hash %abc are: @keys\n");
The result is: a b c@abc = qw(b b c c c a a a);
foreach (@abc) {
$abc_hash{$_} = 1;
}
@unique_array_members = sort(keys %abc_hash);
print ("@unique_array_members\n");
@abc = qw(a a b b b c c);
%unique =();
undef @unique{ @abc };# this sets the values of the hash to 'undef' ;
print (@unique_array_elements = sort(keys %unique));# prints abc
The function 'map' evaluates -by definition- the expression between curly braces in a list context. This means that in fact the following list is returned by the function 'map':%abc_hash = map {$_, 1} @abc;
The result is: a b c%abc_hash = (('b', 1), ('b', 1), ('c', 1), ('c', 1), ('c', 1), ('a', 1), ('a', 1), ('a', 1));
foreach (keys(%abc_hash)) {
print ("$key => $abc_hash{$key}\n");
}
If the increment operator "++" is placed before (prefix form), it increments before returning the value$x = undef;
print ($x++ . "\n");# prints 0; 'undef' has been numifiedstrong>
print ($x);# prints 1
Now another solution to problem of removing duplicates from an array:$j = undef;
print (++$j . "\n");# prints 1
The first time '$member' equals "a", the hash member '$found{"a"}' has no value and is 'undef'. And because 'undef' it is False, '$member' is pushed, i.e. added to the array '@unique' (! is NOT). Then '$found{"a"}' is incremented: 'undef' is numified to 0 and incremented by one. '$found{"a"}' has now the value 1. The second time '$member' equals "a", '$found{"a"}' equals 1, i.e. True. So, 'a' is not added to the array '@unique' and '$found{"a"}' becomes the value 2.@abc = qw (a a b c c c c );
@unique = ();
%found = ();
foreach $member ( @abc ) {
push @unique, $member if (! $found{ $member }++);
}
@abc = qw (a a b c c c c );
@unique = ();
%found = ();
@unique = grep { ! $found{ $_ }++ } @abc;
The 'grep' alternative, a bit slower and without using a hash, is:@abc = qw (a a b c c c c );
%is_found = ();
foreach (@abc) { $is_found{ $_ } = 1 } @abc;
print ("The character 'd' was not found in the array '@abc'\n") if (! $is_found{ 'd' })
print ("The character 'c' was found in the array '@abc'") if ( $is_found{ 'c' })
or shorter:@abc = qw(a a b b b c c);
@matches = grep $_ eq 'a', @abc;
(@matches) ? print "Found!" : print "Not found!";
Advantage: in scalar context you get the number of matches:(grep {/d/} @abc) ? print "Found!" : print "Not found!";
print (scalar (grep /a/, @abc));