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

After learning graphs in Java, I thought I'd try to do the same in perl. I'll admit that I've never tried something that used references as heavily as this, but somehow I expected it to work exactly the way I wanted. I'm also not sure if the first two push statements are doing what I think they do. UPDATE: here is the rest of the source code/ data file
#!/usr/bin/perl -w use strict; use Data::Dumper; @ARGV = 'roads.dat'; my (@lines,@edge,%verts); while(<>){ chomp; push @lines, [split ",", $_]; } map push(@edge, load(@{$_})), @lines; foreach my $edge(@edge){ my($from,$to)=($verts{$edge->{From}},$verts{$edge->{To}}); push @{$from->{Edges}}, $edge; push @{$to->{Edges}}, $edge; print map "$_->{Cost} " , @{$verts{"East Jordan"}->{Edges}}; #print ${$edge}{To}; ${$to}{Cost}=${$from}{Cost}=99999999; } push my @queue, $verts{"East Jordan"}; ${$verts{"Ellsworth"}}{Cost}=0; while(@queue ne 0){ my $town = shift @queue; my $cost = $town->{Cost}; print " | "; print map "$_->{Cost} ", @{$verts{$town}->{Edges}}; foreach(@{$verts{$town}->{Edges}}){ print"[runs]"; my $other = $verts{opposite($_,$town)}; if($cost+$_->{Cost} < $other->{Cost}){ $other->{Cost}=$cost+$_->{Cost}; $other->{Last}=$_; push @queue, $other; } } } print map "$_->{Name} $_->{Cost} $_->{From} $_->{To}\n", @edge; print Dumper(\%verts,\@edge); sub opposite{ if($verts{${$_[0]}{From}} eq $_[1]){ $_[0]->{To}; } elsif ($verts{$_[0]->{To}} eq $_[1]){ $_[0]->{From}; } else { die "opposite failed, ",$!; } } sub load{ {Name => $_[0], Cost => $_[1], From => "$_[2]", To => "$_[3]",}; }
with data file roads.dat
A,5,Ellsworth,East Jordan C,12,Ellsworth,Bellaire B,30,Bellaire,East Jordan D,19,East Jordan,Charleviox E,45,Ellsworth,Elk Rapids F,22,East Jordan,Elk Rapids G,2,East Jordan,Atwood H,14,Atwood,Charleviox

This outputs 12 12 30 12 30 12 30 12 30 12 30 12 30 |

Where if I replace East Jordan with Bellaire, it will print out: 12 12 30 12 30 12 30 12 30 12 30 12 30 | 12 30 runs

And so, if the two strings match, it runs fine, but if they don't, it stops short. But it should work for any string in the data file. What is going on. BTW I'm using 5.8.8 FURTHER UPDATES: print Dumper(\%verts,\@edge); ouputs the following,which makes me wonder why East Jordan never got edge A, as well as how sharing might work in the future.
$VAR1 = { 'HASH(0x9f646ec)' => { 'Edges' => [] }, 'Ellsworth' => { 'Cost' => 0 }, 'East Jordan' => { 'Cost' => 99999999, 'Edges' => [ { 'To' => 'East Jordan', 'Cost' => '30', 'Name' => 'B', 'From' => 'Bellaire' }, { 'To' => 'Charleviox', 'Cost' => '19', 'Name' => 'D', 'From' => 'East Jordan' }, { 'To' => 'Elk Rapids', 'Cost' => '22', 'Name' => 'F', 'From' => 'East Jordan' }, { 'To' => 'Atwood', 'Cost' => '2', 'Name' => 'G', 'From' => 'East Jordan' } ] } }; $VAR2 = [ { 'To' => 'East Jordan', 'Cost' => '5', 'Name' => 'A', 'From' => 'Ellsworth' }, { 'To' => 'Bellaire', 'Cost' => '12', 'Name' => 'C', 'From' => 'Ellsworth' }, $VAR1->{'East Jordan'}{'Edges'}[0], $VAR1->{'East Jordan'}{'Edges'}[1], { 'To' => 'Elk Rapids', 'Cost' => '45', 'Name' => 'E', 'From' => 'Ellsworth' }, $VAR1->{'East Jordan'}{'Edges'}[2], $VAR1->{'East Jordan'}{'Edges'}[3], { 'To' => 'Charleviox', 'Cost' => '14', 'Name' => 'H', 'From' } ];

Replies are listed 'Best First'.
Re: hashref scope
by jethro (Monsignor) on Apr 28, 2010 at 21:05 UTC

    Without knowing what your data structure looks like it is difficult to say how your code should look like. What I can tell you is that your code looks ok at first glance but is hard to read

    Instead of writing ${$other}{Cost} you could write $$other{Cost}, or even better $other->{Cost}

    Do you know about Data::Dumper ? It is an excellent tool to print complicated data structures for debugging. Just add 'use Data::Dumper' at the beginning of your script and you can print out complicated arrays or hashes with print Dumper(\%somehash); or references with print Dumper($referencetosomehash);

    UPDATE: A short test of your complete script brought an error message: Not a HASH reference at ./t7.pl line 12, <> line 8.. Also I don't see where you initialize %verts with any data before you try to access it in line 10.

Re: hashref scope
by GrandFather (Saint) on Apr 29, 2010 at 03:07 UTC

    First off add strictures (use strict; use warnings; - see The strictures, according to Seuss) to your code then fix up the issue with $cost in the nested foreach loop.

    Aside from that, if I run your code with the data you have provided it prints:

    5 Not a HASH reference at C:\Users\Peter\Delme~~\PerlScratch\noname.pl . +..

    The line involved in the error is:

    push @{${$to}{Edges}}, $edge;

    This is not the result you indicate so either the data provided or the code sample you give is not what you actually tested.

    The immediate issue with the sample provided is that your print ... {"Bellaire"}... line autovivifies the Bellaire %verts entry as an array when it should be a hash.

    It may help if you tell us what you are trying to achieve. It is pretty near impossible to tell that from the code and given the code doesn't work ...

    True laziness is hard work
Re: hashref scope
by Anonymous Monk on Apr 28, 2010 at 20:46 UTC
Re: hashref scope
by Anonymous Monk on Apr 29, 2010 at 03:26 UTC

    Since I don't know what you're trying to do, there's no sense attempting to decipher the data structure. However, it looks like the data structure is created (autovivified) inside the for loop and goes out of scope at the end. First, try use strict; and fix all the errors and warnings that come up. Pay attention to the uninitialized value warnings. Then use Data::Dumper as others suggested.