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

I am extracting data and putting it in a hash.

open FH, "$data" or die "Can't open $data: $!"; flock (FH, 1) or die "Can't lock $data for reading: $!"; foreach my $line (<FH>) { (undef,undef,undef,$email,$phone,$partners,$memberno) = split "\t", $l +ine; my @partnerssplit = split / /, $partners; $partners{$memberno} = \@partnerssplit; } close FH; print Dumper( \%partners);
This results in the printout:
$VAR1 = { 'fr065603' => [ 'fr065600' ], 'fr065601' => [ 'fr065600', 'fr065602' ], 'fr065604' => [ 'fr065600' ], 'fr065600' => [ 'fr065601', 'fr065602' ], 'fr065602' => [ 'fr065604', 'fr065603' ] };

Depending on the $level one requests, I would like to look up the values of the codes contained in the array value and extend the hash, extracting the final information as required.

The following snippet achieves the required result but doesnot extend the hash and it can be seen that extending the level would be quite complex

} elsif ($level == 2) { foreach my $item (@{$partners{$base}}) { if (exists $partners{$item}) { push @allmembers1, $item, @{$partners{$item}}; foreach $item1(@allmembers1) { if (exists $partners{$item1}) { push @allmembers, $item1, @{$partners{$item1}}; } } } }
I'd be grateful if someone could point me in the right direction...

Replies are listed 'Best First'.
Re: creating a hash of arrays/hashes
by simonm (Vicar) on Mar 30, 2004 at 18:56 UTC
    A better title for the OP's question would be "Finding all connected nodes in a directed graph". From the "members and partners" language, I'd guess that this is for something like a friend-of-a-friend networking tool

    I'm not entirely sure what "extend the hash" means, but I think you might be well served by looking at the Graph::Base distribution.

    Building the all-pairs shortest-path network might seem like overkill, but if you can find a way to cache that and only rebuild it when the network changes, you should then be able to repeatedly pull out whichever subset you're interested in.

    use Graph::Directed; my $network = Graph::Directed->new(); # Build a directed network of partners and members foreach my $partner ( keys %partners ) { foreach my $item ( @{ $partners{$partner} ) { # Add each pairing as a network edge with weight 1 $network->add_edge( $partner, $item ); $network->set_attribute('weight', $partner, $item, 1); } } # Now build a shortest-path network my $friends = $network->APSP_Floyd_Warshall(); # Now review all of the links in the network my $required_level = 2; my ( @all_levels ) = $friends->edges(); while ( scalar @all_levels ) { my ( $from, $to ) = splice(@all_levels, 0, 2); my $degrees = $friends->get_attribute('weight', $from, $to); next if ( $degrees > $required_level ); push @{ $allmembers{$from} }, $to; }

    At a minimum, take a look at the implementation of APSP_Floyd_Warshall, which seems to be related to what you're looking for.

    I'm hardly a graph-theory expert, so the above might not really be what the OP was asking for... corrections would be welcome. I just knew that there must be an existing implementation for this and searched CPAN for Graph.

Re: creating a hash of arrays/hashes
by Happy-the-monk (Canon) on Mar 30, 2004 at 17:31 UTC

    I would like to look up the values of the codes contained in the array value and extend the hash,

    You forgot to tell us how and what with you want to extend the hash.

    extracting the final information as required.

    Please also enlighten us what "information as required" means in this context.

    The following snippet achieves the required result but doesnot extend the hash and it can be seen that extending the level would be quite complex

    That pushes the key and values onto the array @allmembers. I can't see why you want to do that.

    I am missing a hint towards what you are trying to accomplish, could you specify it some more?

    Cheers, Sören

      The information required is the path connecting the various codes. So if you start at basic level you can see that in the example I gave
      'fr065601' connects to 'fr065600', 'fr065602'
      Now taking it to level 1
      'fr065601' connects to 'fr065600', 'fr065601' , 'fr065602'
      This is found by looking up the values 'fr065600', 'fr065602' as keys in %partners and finding their values.

      This could continue for many levels
      ('fr065601' connects to 'fr065600', 'fr065601' , 'fr065602' , 'fr06560 +4' , 'fr065602' )

      The snippet I included does achieve this for 2 levels