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

I have a hash, %userdatefile which is 3 levels deep, containing one record whose value is the number of times that a user requested a file on a certain date, e.g., it was created via:
++$userdatefile{$USER}{$DATE}{$FILE}
Now the idea is that it would be nice to reorder the hash so that I could make the first key the date instead. I could manually do this, creating another hash, accessible ala:
$dateuserfile{$DATE}{$USER}{$FILE}
but it seems cumbersome and tedious to create new hashes for each dimensional rework of the original dataset.

Can anyone recommend a package/means to have one nested hash yet be able to "query" it for multiple views?

Gracias, pawn

Replies are listed 'Best First'.
Re: creating multiple views of a hash by reordering its key and values
by George_Sherston (Vicar) on Jun 26, 2002 at 10:50 UTC
    Stop me if I'm saying something obvious, but does the plan of your script commit you to this data structure? - if not, would there be any merit in considering an array of hashes? - each hash having the three keys user, date, file. Then it would be easy to grep out the bits you want, e.g.
    @results = grep { $_->{user} eq 'Fred' and $_->{date} >= 1023318000 and $_->{date} <= 1024182000 } @$userdatefile;
    to get everything by Fred between the 6th and 16th of this month.

    § George Sherston
Re: creating multiple views of a hash by reordering its key and values
by bronto (Priest) on Jun 26, 2002 at 10:02 UTC

    Your problem seems well-suited to be treated with object-oriented techniques.

    Hide your data structures into an object, and create methods to get the views you need. You could then implement methods that reorder your hash on the fly or, if memory is not an issue, implement a cache that avoid recalculation of the same hash when not needed -but that would bring you back to the cumbersome and tedious problem to create new hashes for each dimensional rework of the original dataset :-).

    Let me know if I should go further and drop some quick-and-dirty code you can use as starter.

    Ciao!
    --bronto

    # Another Perl edition of a song:
    # The End, by The Beatles
    END {
      $you->take($love) eq $you->made($love) ;
    }

      Howdy!

      This answer doesn't really speak to the core issue -- the data model. See my reply below for more on my point...

      yours,
      Michal

Re: creating multiple views of a hash by reordering its key and values
by Zaxo (Archbishop) on Jun 26, 2002 at 10:21 UTC

    You could just add the new keys to the existing hash and make the same data serve both sets of keys:

    foreach my $user (keys %dateuserfile) { for (keys %{$dateuserfile{$user}}) { $dateuserfile{$_}{$user} = $dateuserfile{$user}{$_}; } }
    I won't vouch for the purity of design, but it ought to be efficient, giving two views of the identical data. Updates from one view will be seen from the other.

    Update: ichimunki, rewrite line 5 as $hash{bar}{foo} = $hash{foo}{bar};. You're copying the value by including the deepest key. Leave off that last key and you get a copy ot the reference to the hash where it lives.

    After Compline,
    Zaxo

      Updates from one view will be seen from the other.

      They will? I tried the following:

      #!/usr/bin/perl -w use strict; my %hash; $hash{foo}{bar}{x} = 'zoom!'; $hash{bar}{foo}{x} = $hash{foo}{bar}{x}; print "$hash{foo}{bar}{x}\n"; print "$hash{bar}{foo}{x}\n"; $hash{foo}{bar}{x} = '!mooz'; print "$hash{foo}{bar}{x}\n"; print "$hash{bar}{foo}{x}\n";
      which outputs:
      zoom! zoom! !mooz zoom!
      Now, if maybe I'm misunderstanding what your code does, but while it gives two separate views of the data, it does not create a duplicate set of references to a single set of data... if my calculations are correct it creates a second copy of the data with new references to the second copy. Changes to one copy will not affect the other.
      update: my fault for not paying attention to details! Thanks for clarifying zaxo. Of course, this is still less than optimal, since it would seem to make doing key reordering impossible for that last key (not that doing this was in the original requirements, but it's the kind of solution I'd be hoping for). Also, we do still have a potential key overwrite going on (think $hash{foo}{foo}{x}).
Re: creating multiple views of a hash by reordering its key and values
by Aristotle (Chancellor) on Jun 26, 2002 at 16:42 UTC

    George_Sherston++

    If you don't want to loose the speed of hash lookups, you might want to store a list of lists ([ $date, $user, $file ], [ ... ], ...) and then have three hashes of lists ( { $date => [ @matching_elems ] }, { ... }, ...) where the @matching_elems might be references to the lists in your master list (faster) or indices into it (more flexible). This is probably ripe ground for use of an object.

    Makeshifts last the longest.

Re: creating multiple views of a hash by reordering its key and values
by herveus (Prior) on Jul 02, 2002 at 17:02 UTC
    Howdy!

    I found this node referenced in the POD for Data::Hash::Flatten.

    The fundamental issue is an inappropriate data structure. Given what you want to do with the data, a HoHoHoH is (as you've discovered) cumbersome for many searches.

    The problem illustrates the weakness of hierarchical databases. Your data model could be restated as a relational table with four columns:

    • user
    • date
    • file
    • count

    The first three items together constitute the "key"; all three are required to uniquely specify a count.

    An array of hashes would be a more useful model, since each count is identified by a combination of user, date, and file. Without all three pinned down, you may have more than one "row" identified.

    An array of arrays would do as well, if you don't mind giving up the symbolic "column" names.

    yours,
    Michael

Re: creating multiple views of a hash by reordering its key and values
by princepawn (Parson) on Oct 21, 2002 at 19:24 UTC
    how could I forget Data::DRef? One of my alltime favorite modules!