2011-01-24 52 views
3

我不知道,如果「擴展」是正確的字,但這裏是我想怎樣做=)如何擴大數組哈希?

這個腳本

#!/usr/bin/perl 

use warnings; 
use strict; 

my %HoA = (
    group1 => [ "user1", "user2" ], 
    group2 => [ "group1", "user3" ], 
    group3 => [ "group1", "group2" ], 
    group4 => [ "group3", "user2" ], 
    ); 

foreach my $group (keys %HoA) { 
    print "$group: @{ $HoA{$group} }\n" 
} 

輸出

group1: user1 user2 
group2: group1 user3 
group3: group1 group2 
group4: group3 user4 

我希望是用成員替換數組中的組。即所以輸出和$HoA成爲

group1: user1 user2 
group2: user1 user2 user3 
group3: user1 user2 user3 
group4: user1 user2 user3 user4 

也許「查找和替換」並刪除重複將是我想做些什麼更好的解釋?

+2

如果你有循環引用?即如果group1有group2,group2有group1呢? – CanSpice 2011-01-24 21:52:33

+0

然後我想運送該組,並打印一個錯誤。 – 2011-01-24 21:53:52

回答

3

假設您給出的數據,下面的循環將使用展開的數組創建一個新的散列。該算法假定組將按排序順序進行解析(組2將僅取決於組1,組1將取決於組1,組2)。

my %expanded; 
for my $group (sort keys %HoA) { 
    my %seen; 
    $expanded{$group} = [ 
     grep {not $seen{$_}++} 
     map {exists $expanded{$_} ? @{$expanded{$_}} : $_} 
     @{$HoA{$group}} 
    ]; 
    print "$group: @{ $expanded{$group} }\n" 
} 

它打印:

 
group1: user1 user2 
group2: user1 user2 user3 
group3: user1 user2 user3 
group4: user1 user2 user3 

如果您不能承擔解析順序,以下是有點蠻力,但應該工作:

my %HoA = (
    group1 => [ "user1", "user2" ], 
    group2 => [ "group1", "user3" ], 
    group3 => [ "group1", "group2" ], 
    group4 => [ "user5", "group5" ], 
    group5 => [ "group3", "user2" ], 
    ); 

my @to_expand = keys %HoA; 

my %final; 
my $tries = @to_expand; 
to_expand: while (@to_expand and $tries) { 
    my $next = shift @to_expand; 

    my (@users, @groups); 
    for (@{ $HoA{$next} }) { 
     if (/^group/) { 
      push @groups, $_; 
     } else { 
      push @users, $_; 
     } 
    } 
    for my $group (@groups) { 
     if (exists $final{$group}) { 
      push @users, @{$final{$group}} 
     } else { 
      $tries--; 
      push @to_expand, $next; 
      next to_expand; 
     } 
    } 
    $tries++; 
    my %seen; 
    $final{$next} = [grep {not $seen{$_}++} @users]; 
} 
if (@to_expand) { 
    print "error with groups: @to_expand\n"; 
} 

for (sort keys %final) { 
    print "$_: @{$final{$_}}\n"; 
} 

它打印:

 
group1: user1 user2 
group2: user3 user1 user2 
group3: user1 user2 user3 
group4: user5 user2 user1 user3 
group5: user2 user1 user3 

如果有錯誤或(說的第3組取決於組5),那麼你會得到這樣的輸出:

 
error with groups: group4 group5 group3 
group1: user1 user2 
group2: user3 user1 user2 

有更好的算法可能是在那裏這一點。

+0

我真的不能做出這樣的假設=(這些組可以包含任何組合的對方,非常令人印象深刻的腳本都不會少! – 2011-01-24 22:18:20

3

如果有遞歸這將拋出一個錯誤 - 不是萬無一失的,而不是優雅的版本,雖然

use strict; 

my %HoA = (
    group1 => [ "user1", "user2" ], 
    group2 => [ "group1", "user3" ], 
    group3 => [ "group1", "group2" ], 
    group4 => [ "group3", "user2" ], 
    ); 

my %ex=(); # expanded hash 

foreach my $g (keys %HoA) { # first population 
    $ex{$g} = {}; 
    AddArrayToHash($ex{$g},$HoA{$g}); 
} 
my $goon = 1; 
my $cont =0; 
while($goon) { # iterate 
    $goon=0; 
    die "too many iterations RECURSIVE DEFINITION?" if($cont++ >10) ; 
    foreach my $g (keys %ex) { 
     foreach my $u (keys %{$ex{$g}}) { 
      if($ex{$u}) { 
       delete $ex{$g}->{$u}; 
       AddArrayToHash($ex{$g},[ keys %{$ex{$u}}]); 
       $goon = 1; 
      } 
     } 
    } 
} 

foreach my $group (sort keys %ex) { 
    print "$group: " . join(" ",sort keys %{$ex{$group}}) ."\n"; 
} 

sub AddArrayToHash { 
    my($refhash,$refarray)[email protected]_; 
    foreach my $e (@$refarray) { 
     $refhash->{$e} = 1; 
    } 
} 
2

我不知道爲什麼人們不得不寫了這麼多代碼:

sub expand_group { 
    my ($ref, $arref, $deep) = @_; 
    croak 'Deep Recursion!' if ++$deep > scalar(keys %$ref); 
    return map { 
     exists $ref->{$_} ? expand_group($ref, $ref->{$_}, $deep) : $_ 
    } @$arref 
    ; 
} 

sub expand_groups { 
    my ($block, $group_ref) = @_; 
    while (my ($key, $val) = each %$group_ref) { 
     $block->($key, expand_group($group_ref, $val, 1)); 
    } 
} 

expand_groups(sub { say join(' ', @_); }, \%HoA); 
2

我想嘗試像

#!/usr/bin/perl 

use warnings; 
use strict; 

my %HoA = (
    group1 => [ "user1", "user2" ], 
    group2 => [ "group1", "user3" ], 
    group3 => [ "group1", "group2" ], 
    group4 => [ "group3", "user2" ], 
    ); 


my %users; 

foreach my $group (sort keys %HoA) { 
    %users =(); 

    print "$group: "; 
    print_key($group, $HoA{$group}); 
    print join " ", sort keys %users; 
    print "\n"; 
} 

sub print_key { 
    my $group = shift; 

    foreach my $item (@{$HoA{$group}}) { 
    if (exists $HoA{$item}) { 
     print_key($item); 
    } 
    else { 
     $users{$item}++; 
    } 
    } 
}