A hash is data structure that stores one or more key/value pairs. Variables whose names begin with % are hashes, also called associative arrays.
The variable %color is a hash, which is different from $color, though members of %color are selected by $color{$key}.
Two remarks:
Hashes can also be defined in other ways. However, I prefer this way: clean and readable.
%authors_books = (
'Scott Fitzgerald' => 'The Great Gatsby',
'John Steinbeck' => 'The Grapes of Wrath',
'Ernest Hemingway' => 'The Old Man and the Sea' );
%authors_books_1 = (
'Scott Fitzgerald' => 'The Great Gatsby',
'John Steinbeck' => 'The Grapes of Wrath' );
%authors_books_2 = (
'Ernest Hemingway' => 'The Old Man and the Sea',
'Mark Twain' => 'The Adventures of Huckleberry Finn' );
%combined_hash_authors_books = (%authors_books_1, %authors_books_2);
To make a partial copy:
%copy_authors_books = %authors_books;
%partial_copy_authors_books = %authors_books{'Scott Fitzgerald', 'John Steinbeck'};
%copy_authors_books = ();
Notice the curly braces: $authors_books{'Ernest Hemingway'}.
print($authors_books{'John Steinbeck'} . "\n");# notice the $
print("The best book of Hemingway is '" . $authors_books{'Ernest Hemingway'} . "'\n");
Notice the use of @
print("@authors_books{'Scott Fitzgerald', 'John Steinbeck'}");# output: The Great Gatsby The Grapes of Wrath
Notice that you've -if you run this many times- again and again different results, i.e. the order of the key/value pair is not according your hash definition AND has different order. To avoid this problem, use sort:
@keys = keys(%authors_books);# notice the @
print("Keys of the hash %authors_books are: @keys\n");
Study Chapter 1.5.4 on Sort.
@keys = sort(keys(%authors_books));
print("Keys of the hash %authors_books are: @keys\n");
$no_elements = keys(%authors_books);
You could also iterate over the values of a hash:
foreach $author (keys(%authors_books)) {
print("$author => $authors_books{$author}\n");# or: print($author . " => " . $authors_books{$author} . "\n");
}
foreach $title (values(%authors_books)) {
print($title ."\n");
}
sub six_outof_fortynine { my %h; while (keys %h < 6) { nicely done! $h{int(rand(48))+1}++; } return sort {$a <=> $b} keys %h; } for my $i (1..10) { printf "%2d %s\n", $i, join('-', map { sprintf("%2d", $_) } six_outof_fortynine()); }
$str = "reinier"; %count = (); foreach $char (split(//, $str)) { $count{$char}++; } foreach $key (keys(%count)) { print("$key => $count{$key}\n"); # Output: i => 2 n => 1 e => 2 r => 2 }
You can also use a hash-slice:
%copy_authors_books = %authors_books;
$copy_authors_books{'Herman Melville'} = 'Moby-Dick';
Notice that adding a new member with an existing key will overwrite the old member. Unique keys is one of the niceties of hashes.
%copy_authors_books = ();
@copy_authors_books{'Scott Fitzgerald', 'John Steinbeck'} = ('Tender Is the Night', 'East of Eden');
Better (check first if the element exists):
%copy_authors_books = %authors_books;
delete($copy_authors_books{'John Steinbeck'});
Or (check with exists):
%copy_authors_books = %authors_books;
delete($copy_authors_books{'John Steinbeck'}) if ($copy_authors_books{'John Steinbeck'})
%copy_authors_books = %authors_books;
delete($copy_authors_books{'John Steinbeck'}) if (exists $copy_authors_books{'John Steinbeck'})
Chapter 1.5.5 shows how to change multiple values with 'foreach'.
%copy_authors_books = %authors_books;
$copy_authors_books{'Herman Melville'} = 'Pierre';
Also possible:
@keys = sort(keys(%authors_books) );
print("Keys of the hash %authors_books are: @keys\n");
For sorting hashes via possibly not unique values, you need a specific sort-function (low to high):@keys = reverse ( sort(keys(%authors_books) );
print("Keys of the hash %authors_books are: @keys\n");
To sort in a reverse order (high to low), change the position $a and $b in the sort-function 'sort_values':
%students_math_test = (
'Student_1' => '6.1',
'Student_2' => '4.3',
'Student_3' => '6.1',
'Student_4' => '7.2' );
sub sort_values {
return $students_math_test{$a} <=> $students_math_test{$b}
}
foreach $student (sort sort_values keys(%students_math_test)) {
print($student . " " . $students_math_test{$student} . "\n");
}
The variables $a and $b are built-in, so do not give them your own variablenames.
sub sort_values {
return $students_math_test{$b} <=> $students_math_test{$a}
}
%students_math_test = (
'Student_1' => '6.1',
'Student_2' => '7.3',
'Student_3' => '9.2' );
I want to add 0.2 to the test scores:
$sum = 0;
$count = 0;
foreach $score (values(%students_math_test)) {
$sum += $score;
$count++;
}
$average = $sum/$count;
print($average . "\n");# result: 7.53333333333333
printf("%.1f\n", $average);# result: 7.5
Now the hash has modified values!
foreach $score (values(%students_math_test)) {
$score += 0.2;
}
Notice that I do not recommend to use 'each': while running a hash programm, unexpected behaviour will arise when you change the hash (adding or deleting hash members).
%students_math_test = (
'Student_1' => '6.3',
'Student_2' => '7.5',
'Student_3' => '9.4' );
%hash = (); @list = ('a'..'d'); $id = 0; foreach $value (@list) { $id++; $hash{"key_" . $id} = $value; } foreach $key ( sort( keys(%hash) ) ) { print("$key => $hash{$key}\n"); } Output: key_1 => a key_2 => b key_3 => c key_4 => d
@list = (); %hash = ( key_1 => 'a', key_2 => 'b', key_3 => 'c', key_4 => 'd' ); @list = sort( values(%hash) ); print("@list\n"); # Output: a b c d
To make a list of strings:%hash = ( key_1 => 'a', key_2 => 'b', key_3 => 'c', key_4 => 'd' ); $mc_keys = join(', ', sort( keys(%hash) ) ); print("$mc_keys\n"); # Output: key_1, key_2, key_3, key_4
%hash = ( key_1 => 'a', key_2 => 'b', key_3 => 'c', key_4 => 'd' ); @arr = map {"[ $_: " . uc($hash{$_}) . " ]"} sort(keys(%hash)); print("@arr\n"); # Output: [ key_1: A ] [ key_2: B ] [ key_3: C ] [ key_4: D ]