Ward Number In Perl

See WardNumber for the problem definition.

See WardNumberInManyProgrammingLanguages for many other implementations.


PerlLanguage

    use strict;
    my (%partners, %wardnumber, $p);

sub visit { my ($cnt, @closer_folks) = @_; my @newfolks; foreach my $i (@closer_folks) { foreach my $j (@{$partners{$i}}) { unless ($wardnumber{$j}) { $wardnumber{$j} = $cnt; push @newfolks, $j; } } } visit (++$cnt, @newfolks) if @newfolks; }

sub pair { push @{$partners{$_[0]}}, $_[1]; }

open FS, "data.txt"; while (<FS>) { if (/\s*(.*)\s*,\s*(.*)\s*/) { pair($1,$2); pair ($2,$1); } }

visit(1, 'ward'); foreach $p (sort keys %wardnumber) { print "$p $wardnumber{$p}\n"}


Here's another one by JohnDouglasPorter

    my %g; # the graph.

# parsing is not interesting. for ( "al bob", "bob cal", "cal dave", "dave ed ", "cal fred", "al ward", "dave ward", ) { my( $x, $y ) = split; $g{$x}{$y}++; $g{$y}{$x}++; }

sub graph_distance # BFS { my( $goal, $n ) = @_; my @try_paths = ( [$n] ); while ( @try_paths ) { my @path = @{ shift @try_paths }; $path[0] eq $goal and shift @path, return @path; my %path_nodes; @path_nodes{ @path } = (); my @next = grep { ! exists $path_nodes{$_} } keys %{ $g{$path[0]} }; @next and push @try_paths, map { [ $_, @path ] } @next; } die "No path from $n to $goal.\n"; }

my $n = 'ward'; my $wwnum = graph_distance( $n ); print "Ward number for $n is $wwnum\n";


And another by TonyBowden?:

  #!/usr/bin/perl -w

use strict; use Class::Struct Programmer => { wardno => '$', pairs => '@' }; use List::Util 'min';

my @pairs = qw/al bob bob cal cal dave dave ed cal fred al ward dave ward/;

sub Programmer::add_pair { my ($self, $prog) = @_; $self->pairs([ @{$self->pairs}, $prog ]); }

my %prog; while (my ($x, $y) = map $prog{$_} ||= Programmer->new, splice @pairs, 0, 2) { $x->add_pair($y); $y->add_pair($x); } $prog{ward}->wardno(0);

while (my @need = grep !defined $_->wardno, values %prog) { foreach my $prog (@need) { my @known = grep defined, map $_->wardno, @{ $prog->pairs } or next; $prog->wardno(1 + min @known); } }

sub ward_number { $prog{+shift}->wardno }


TMTOWTDI - here's one by AristotlePagaltzis:

This one calculates everyone's WardNumber with regard to the target programmer at once. The edge_distance() function here can actually be used on any graph where all edges are bidirectional.

  #!/usr/bin/perl
  use strict;
  use warnings;

# idiomatic Perl sub flatten_hashrefs { return map { keys %{$_} } @_; }

# very common idiom sub list_contains { my ($element, @list) = @_; return scalar grep $_ eq $element, @list; }

# hash of hashes that stores the graph my %connections_of;

sub connected_to { return flatten_hashrefs( @connections_of{@_} ); }

sub edge_distance { my ($initial_node, $target_node) = @_;

my %seen; my $wnum = 0; my @occupied_node = ( $initial_node );

do { # nodes we occupy have been seen ++$seen{$_} for @occupied_node;

# occupy connected nodes, except those we've seen before @occupied_node = grep { !$seen{$_} } connected_to( @occupied_node );

# undefined edge distance if no route to target return if not @occupied_node;

++$wnum; } until( list_contains( $target_node, @occupied_node ) );

return $wnum; }

# read graph data while(<DATA>) { my ($from, $to) = split; ++$connections_of{$from}{$to}; ++$connections_of{$to}{$from}; }

my $TARGET = shift( @ARGV ) || 'Ward';

for( keys %connections_of ) { my $wnum = edge_distance( $_, $TARGET ); print defined( $wnum ) ? "$wnum edges between $_ and $TARGET\n" : "No route from $_ to $TARGET\n"; }

__END__ Al Ward Joe John Al Bob Bob Cal Cal Dave Joe Peter Ray Peter Dave Ed Cal Fred Dave Ward


I think I would use Graph from CPAN: http://search.cpan.org/dist/Graph/


CategoryPerl


EditText of this page (last edited January 3, 2005) or FindPage with title or text search