in reply to Creating an array of hash references

Sounds like you have to store the data directly, then munge through it to extract the key/value pair at a later point.
my @data = (); my @final = (); while (!$client->timeout()) { my $stream = $client->get_data(); push(@data,$stream); } foreach (@data) { push(@final,munge($_)); #<-- push hash ref onto @final } sub munge { my %hash = (); #...create hash return \%hash; #<-- hash ref }

Replies are listed 'Best First'.
Re^2: Creating an array of hash references
by Bobc (Initiate) on Mar 17, 2005 at 18:46 UTC
    Thanks to all for the replies. I see now that I did not make my problem clear enough. My script is accessing a company-proprietary package that interfaces with the server. The "Read()" routine from the package returns a hash. Depending on the event being read, the hash will have a different set of key/value pairs, but each hash contains an ID key/value pair so that the calling code can process the data correctly:
    my %event = SECRET_PACKAGE_NAME::WaitForEvent($timeout);
    My script is initiating an action which causes the server to spit out data at a much higher rate than normal. Originally I was reading a single hash and processing it real-time. Running some external diagnostics showed that I was missing some key data, so I decided to run a tight loop to collect ALL the data. I tried the following which didn't work:
    my @Events; while(1) { my %event = (); eval { %event = SECRET_PACKAGE_NAME::WaitForEvent($timeout); }; if($@) { # timeout occurred, serial burst complete last; } else { push (@Events, \%event); } }# end while ... while(@Events) { # Get the first event, NOT the last one my $EventRef = shift(@Events); } # $EventRef points to garbage
    Does this clarify my issue? I need to preserve all the key/value pairs of the received data somehow so that I can post-process the information. Thanks again for the responses

      Nothing looks wrong here. I mean, I would clean it up differently, but functionally, it seems ok.

      use Data::Dumper; # ... my @Events; while (1) { eval { my %event = SECRET_PACKAGE_NAME::WaitForEvent($timeout); push @Events, \%event; print LOG Dumper(\%event); }; last if $@; } print LOG "=======\n", Dumper(\@Events);
      Take the dumper lines out once you're convinced everything is working fine. But I would be extremely interested in whether there is a difference here or not. I expect no difference, and thus the problem is that the WaitForEvent sub is returning garbage (or returning something that isn't really a hash list).

      That's just my gut feel on it...

        Thanks for the replies. It turns out the problem was when I initialized the array to hold the references, I stupidly added a blank entry, so when I started pushing to the array it already had an entry. Duh. So my parsing routine puked at the first value, and when I examined the array, I looked at the first value, saw it was garbage. Thanks for putting me on the right track!
      update: As pointed out below by Tanktalus, the information in this reply is basically wrong. Please ignore it.

      I think what's wrong there is that you're pushing the same reference to the same hash over and over onto your array, and also clearing and refilling that hash on each iteration.

      What you probably want to do instead is push a reference to an anonymous copy of "%event":

      while(1) { my %event = (); eval { %event = SECRET_PACKAGE_NAME::WaitForEvent($timeout); }; if($@) { # timeout occurred, serial burst complete last; } else { push (@Events, { %event }); } }# end while ...
      (I could be wrong, but I think this is worth a try.)

        Nope - each time through the while loop, you're getting a new %event - each one gets its own address allocated. If the "my" were outside of the while loop, you'd be right. As it is, all your change accomplishes is to copy the hash around an extra time (into an anonymous reference) more than is required.

        (If there is no reference to the %event, the perl VM may optimise it away and just refill the same one, but since the OP is taking a reference to it which lasts through the end of the loop, perl cannot make that optimisation, and allocates a new one.)