You want to iterate over
keys %inventory
and not
%inventory
which, as you see, causes you to iterate over key, value pairs.
You want to iterate over
keys %inventory
and not
%inventory
which, as you see, causes you to iterate over key, value pairs.
You're using your hash in list context, so you're getting all your values thrown in with your keys. I think what you actually want to do is:
foreach $key (keys %inventory) {
print FILE "...";
}
EDIT: I was wrong about having to use an explicit dereferencing arrow; this is inferred between brackets when necessary, even if the first brackets do NOT require a dereference. That said, I will leave the remainder of the answer as posted since it was accepted, but merely note that if you choose not to use join
, you needn't actually use $inventory{$key}->[0]
but can in fact use $inventory{$key}[0]
as originally posted.
Just be aware that the first (hash) brackets do not imply a dereference but the second (array) brackets do. Your errant array refs in the output were coming from looping over not only keys but also values of the hash.
ORIGINAL ANSWER:
In addition to using keys
, you also need to dereference the references-to-array (this is why you're seeing each value output as ARRAY with an address---you're printing the references, not the values of the dereferenced array) when you print, so your loop becomes something like:
foreach my $key (sort keys %inventory) {
print FILE "$key\|$inventory{$key}->[0]\|$inventory{$key}->[1]\|$inventory{$key}->[2]\n";
}
I'd probably rewrite it a little more idiomatically as:
foreach my $key (sort keys %inventory) {
print FILE (join '|', $key, @{$inventory{$key}}) . "\n";
}
Hope that helps!
Here is one way to write that routine:
#!/usr/bin/perl
use strict; use warnings;
my %inventory;
while ( my $line = <DATA> ) {
chomp $line;
my ($key, @values) = split qr{\|}, $line;
last unless @values;
$inventory{$key} = \@values;
}
write_inventory(\%inventory, 'test.txt');
sub write_inventory {
my ($inventory, $output_file) = @_;
open my $output, '>', $output_file
or die "Cannot open '$output_file': $!";
for my $item ( keys %$inventory ) {
unless ( 'ARRAY' eq ref $inventory{$item} ) {
warn "Invalid item '$item' in inventory\n";
next;
}
print $output join('|', $item, @{ $inventory{$item} }), "\n";
}
close $output
or die "Cannot close '$output': $!";
}
__DATA__
CD-911|Lady Gaga - The Fame|15.99|21
BOOK-1453|The Da Vinci Code - Dan Brown|14.75|12
Don't use global variables: Pass a reference to %inventory
to write_inventory
instead of having it operate on the global %inventory
.
Don't use global variables: Instead of using the bareword file handle FILE
which has package scope, use a lexical file handle whose scope is limited to write_inventory
.
Check for errors on file operations: Make sure open
succeeded before plowing ahead and trying to write. Make sure close
succeeded before assuming all data you printed actually got saved.
You MUST use strict and warnings because, at this point in your learning process, you do not know enough to know what you do not know.o