11.9. Constructing RecordsProblemYou want to create a record data type. SolutionUse a reference to an anonymous hash. DiscussionSuppose you wanted to create a data type that contained various data fields, akin to a C $record = {
NAME => "Jason",
EMPNO => 132,
TITLE => "deputy peon",
AGE => 23,
SALARY => 37_000,
PALS => [ "Norbert", "Rhys", "Phineas"],
};
printf "I am %s, and my pals are %s.\n",
$record->{NAME},
join(", ", @{$record->{PALS}});Just having one of these records isn't much fun - you'd like to build larger structures. For example, you might want to create a # store record
$byname{ $record->{NAME} } = $record;
# later on, look up by name
if ($rp = $byname{"Aron"}) { # false if missing
printf "Aron is employee %d.\n", $rp->{EMPNO};
}
# give jason a new pal
push @{$byname{"Jason"}->{PALS}}, "Theodore";
printf "Jason now has %d pals\n", scalar @{$byname{"Jason"}->{PALS}};That makes We can use our existing hash tools to manipulate # Go through all records
while (($name, $record) = each %byname) {
printf "%s is employee number %d\n", $name, $record->{EMPNO};
}What about looking employees up by employee number? Just build and use another data structure, an array of hashes called # store record
$employees[ $record->{EMPNO} ] = $record;
# lookup by id
if ($rp = $employee[132]) {
printf "employee number 132 is %s\n", $rp->{NAME};
}With a data structure like this, updating a record in one place effectively updates it everywhere. For example, this gives Jason a 3.5% raise: $byname{"Jason"}->{SALARY} *= 1.035;This change is reflected in all views of these records. Remember that both How would you select all records matching a particular criterion? This is what @peons = grep { $_->{TITLE} =~ /peon/i } @employees;
@tsevens = grep { $_->{AGE} == 27 } @employees;Each element of Here's how to print all records sorted in a particular order, say by age: # Go through all records
foreach $rp (sort { $a->{AGE} <=> $b->{AGE} } values %byname) {
printf "%s is age %d.\n", $rp->{NAME}, $rp->{AGE};
# or with a hash slice on the reference
printf "%s is employee number %d.\n", @$rp{'NAME','EMPNO'};
}Rather than take time to sort them by age, you could just create another view of these records, # use @byage, an array of arrays of records
push @{ $byage[ $record->{AGE} ] }, $record;Then you could find them all this way: for ($age = 0; $age <= $#byage; $age++) {
next unless $byage[$age];
print "Age $age: ";
foreach $rp (@{$byage[$age]}) {
print $rp->{NAME}, " ";
}
print "\n";
}A similar approach is to use for ($age = 0; $age <= $#byage; $age++) {
next unless $byage[$age];
printf "Age %d: %s\n", $age,
join(", ", map {$_->{NAME}} @{$byage[$age]});
} |