esddew has asked for the wisdom of the Perl Monks concerning the following question:

I'm writing a script where I need to take rows of data and turn them into columns. A hash of arrays seemed like the obvious data structure to use, however I am having some problems getting the data back out.

Here is the problem snippet of code:

foreach $head (keys %hoa) { my @data = @{$hoa{$head}}; $item = shift(@data); print OUTFILE "$item"; print OUTFILE ","; }

This dies with the error "Use of uninitialized value in string at..." and gives the line number of the line with the shift command. However, if I comment out the next line, the print of $item, the script seems to run just fine. If I print @data, that seems to work fine too. I've read the other nodes of for more info on hashes or arrays and I'm stumped.

One other thing I should mention: I've been writing Perl scripts that run on Unix and Mac OSX for a while. This is the first one I've tried writing to run on Windows. I've already run into a few minor yet irritating differences. I'm not sure if this is one of them or not, but if it matters I'm trying to run this under ActivePerl 5.8.8

Replies are listed 'Best First'.
Re: Hash of arrays.. can't shift on derefferenced array
by ikegami (Patriarch) on Mar 28, 2007 at 15:05 UTC

    gives the line number of the line with the shift command.

    I'm not sure what would cause that, but the warning is indeed originating from "$item". $item contains undef, either because the first element of @data was undef before the shift, or because @data was empty before the shift.

    By the way, shifting out of @data will not effect @{$hoa{$head}}. You need to shift from @{$hoa{$head}} directly to do that.

    $\ = "\n"; { my %hoa = ( head => [ 'abc', 'def' ] ); print shift(@{$hoa{head}}); # abc print @{$hoa{head}}; # def -> ok } { my %hoa = ( head => [ 'abc', 'def' ] ); my $data = $hoa{head}; print shift(@$data); # abc print @{$hoa{head}}; # def -> ok } { my %hoa = ( head => [ 'abc', 'def' ] ); my @data = @{$hoa{head}}; print shift(@data); # abc print @{$hoa{head}}; # abcdef -> BAD! }
Re: Hash of arrays.. can't shift on derefferenced array
by Eimi Metamorphoumai (Deacon) on Mar 28, 2007 at 14:55 UTC
    Are you sure you're actually getting the result you think you're getting? Specifically, it really sounds like the line number should correspond to your print "$item"; line. And "Use of uninitialized value in string at..." is a warning, not an error (unless you're doing something strange). I'd suggest that you look at what exactly is in your hoa before the loop. Here's test code that works just fine.
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %hoa = ( a => ["apple", "aardvark"], b => ["banana", "bandana"], ); foreach my $head (keys %hoa) { my @data = @{$hoa{$head}}; my $item = shift(@data); print "$item,"; } print $/;
    which produces as output
    apple,banana,
Re: Hash of arrays.. can't shift on derefferenced array
by agianni (Hermit) on Mar 28, 2007 at 14:54 UTC

    Try pushing the values onto your array:

    my @data; foreach $head (keys %hoa) { push @data, $hoa{$head}; $item = shift(@data); print OUTFILE "$item"; print OUTFILE ","; }

    For your specific example, this would work just as well:

    print OUTFILE join ',' values %hoa;
    If you really want to do what you're trying to show (creating an array with one item and then removing that item), you would have to:
    foreach $head (keys %hoa) { my @data = ( $hoa{$head} ); $item = shift(@data); print OUTFILE "$item"; print OUTFILE ","; }

    Update: I just realized what you were trying to do :) I'm assuming %hoa is actually a hash of arrayrefs, right? I'm guessing that something is actually going on with the construction of your HoA such that your hash entries are actually pointing at undef instead of the arrayrefs you are expecting. Try using Data::Dumper to dump out %hoa before you try to access its content. Can you post the code that you are using to build %hoa?

    perl -e 'split//,q{john hurl, pest caretaker}and(map{print @_[$_]}(joi +n(q{},map{sprintf(qq{%010u},$_)}(2**2*307*4993,5*101*641*5261,7*59*79 +*36997,13*17*71*45131,3**2*67*89*167*181))=~/\d{2}/g));'