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

I have a hash for storing the userid, managerid pair. The data is something like this:
{UserId} => ManagerId
{1234} => "6789" {1235} => "6790" {6789} => "6791" {1236} => "6789"
I need to insert data for each user. But, the problem is if I try to insert data for the 1'st record (userid:1234), it won't allow me because the data for its manager(i.e. 6789) is not yet inserted. The data for this manager comes later in the hash (i.e. record 3)
Can someone suggest me a way so that I insert data for all the managers first & then their subordinates?

Replies are listed 'Best First'.
Re: Problem with hash
by pelagic (Priest) on Apr 19, 2004 at 10:51 UTC
    As still nobody has a really good solution for that hierarchy sort problem I had to hack the following:
    #!/usr/bin/perl use strict; use Data::Dumper; my $form = "%30s %s\n"; my %upgrades; my %lvl; my %PofC = ( 1 => 2 , 3 => 2 , 4 => 2 , 2 => 5 , 6 => 5 , 7 => 4 , 5 => undef , 8 => 4 ); print Dumper \%PofC; foreach my $child (keys %PofC) { $lvl{$child} = 0; } my $leftovers = 1; my $level = 0; while ($leftovers > 0) { %upgrades = (); $leftovers = 0; foreach my $child (keys %PofC) { if (exists $lvl{$PofC{$child}} && $lvl{$PofC{$child}} == $level) { $upgrades{$child} = 1; ++$leftovers; } } foreach (keys %upgrades) { ++$lvl{$_}; } ++$level; } print Dumper \%lvl; printf $form, 'child', 'parent'; foreach my $c ( sort { $lvl{$a} <=> $lvl{$b} } keys %lvl ) { printf $form, $c, $PofC{$c}; } exit; __OUTPUT__ # %PofC $VAR1 = { 1 => 2, 2 => 5, 3 => 2, 4 => 2, 5 => undef, 6 => 5, 7 => 4, 8 => 4 }; # %lvl $VAR1 = { 1 => 2, 2 => 1, 3 => 2, 4 => 2, 5 => '0', 6 => 1, 7 => 3, 8 => 3 }; child parent 5 2 5 6 5 4 2 3 2 1 2 7 4 8 4

    pelagic
      Thanks a lot for your solution!!!
Re: Problem with hash
by ozone (Friar) on Apr 19, 2004 at 08:58 UTC

    one way is to use a recursive sub, that 'walks' up the userid tree until it reaches a node without a manager (or a special id (like 0 or undef)

    the other way is do the same as above, but use a stack and a loop

    some pseudo code

    # simple recursive sub sub create_users { my $user_href = shift; my $userId = shift; if(defined $user_href->{$userId} and $user_href->{$userId} != 0) { create_users($user_href, $userId); } else { return; } # now write the user to the db write_user_to_db($user_href, $userId }

    I think the above should work :-)

Re: Problem with hash
by Zaxo (Archbishop) on Apr 19, 2004 at 09:04 UTC

    Highly data dependent, but it looks like reverse sorting the keys you want will get the managers in first.

    On the other hand, I don't see why you need to have a key in place before you duplicate it as a value. Writing,

    my %organization = ( 1234 => '6789', 1235 => "6790', 6789 => '6791', 1236 => '6789', );
    works fine. If you mean to have values as references to other hash elements, yes, the order matters, but that brings in concerns about circular references also. (Shouldn't be a problem with a proper tree.)

    After Compline,
    Zaxo

Re: Problem with hash
by thor (Priest) on Apr 19, 2004 at 12:39 UTC
    There's something that you're not telling us. Hashes by themselves don't care about the data that's placed in to them. So, you must've imposed that restriction yourself. To which I would reply "don't do that". :) If all of your inserts in to the hash happen at the same time (or to be more precise, happen one after the other without anything in between), I'd do all of my inserts, and then an integrity check at the end. Something simple...like this:
    foreach my $emp (values %hash) { print "ERROR: $emp not defined\n" unless exists($hash{$emp}); }

    thor