我怎样才能循环到数组哈希的散列?

时间:2014-05-21 19:45:05

标签: arrays perl hash cvs perl-data-structures

我试图编写脚本来下载我的CVS模块及其各自的依赖项,我将项目组织成我的Perl脚本的哈希:

$num_args = $#ARGV + 1;

$products = {
    'productName' => {
        'repository1' => ('module1', 'module2'),
        'repository2' => ('module3', 'module4', 'module5'),
        'repository3' => ('module6', 'module7')
    }
};

if ($num_args <= 2) {
    print "($num_args) Insufficient arguments!\n";
    print "Usage: cp-stack.pl PRODUCT_NAME USER [PASSWORD [BRANCH]]\n";
    exit;
}

$Product = $ARGV[0];
$User = $ARGV[1];
$Password = '';
$Branch = '';

if ($num_args >= 3) {
    $Password = $ARGV[2];
}
if ($num_args >= 4) {
    $Branch = $ARGV[3];
}
$productFound = 0;

for my $firstKey (keys %$products) {
    my $productName = $firstKey;
    my $productHash = $products{$productName};
    print "$productName\n";
    if ($productName == $Product) {
        $productFound = 1;
        print "Product '$productName' found!\n";
        print $products{$productName} . " keys\n";
        for my $secondKey (keys %{ $productHash }) {
        #while (my($repository, $modulesList) = each(%$productHash)) {
            my $repository = $secondKey;
            my $modulesList = $productHash{$repository};
            printf("set CVSROOT=:pserver:$User\@mycvsaddr.com:/cvsdirectory/$repository\n");
            for my $i (0 .. $#modulesList) {
                if ($Branch != '') {
                    printf("cvs checkout -P -r {$Branch} " . $modulesList[$i] . "\n");
                } else {
                    printf("cvs checkout -P " . $modulesList[$i] . "\n");
                }
            }
        }
    }
}

它遇到了Product&#39; name&#39;找到了!但是不要进入模块循环......我无法弄明白为什么。

我是Perl的初学者。

3 个答案:

答案 0 :(得分:2)

'repository1' => ('module1', 'module2'),
'repository2' => ('module3', 'module4', 'module5'),
'repository3' => ('module6', 'module7')

相同
'repository1', 'module1', 'module2', 'repository2', 'module3',
'module4', 'module5', 'repository3', 'module6', 'module7'

所以

$products = {
    'productName' => {
        'repository1' => ('module1', 'module2'),
        'repository2' => ('module3', 'module4', 'module5'),
        'repository3' => ('module6', 'module7')
    }
};

是一种奇怪的写作方式

$products = {
    'productName' => {
        'repository1' => 'module1',
        'module2'     => 'repository2',
        'module3'     => 'module4',
        'module5'     => 'repository3',
        'module6'     => 'module7',
    }
};

你永远不会创建任何阵列!您可以使用方括号创建匿名数组。

$products = {
    'productName' => {
        'repository1' => [ 'module1', 'module2' ],
        'repository2' => [ 'module3', 'module4', 'module5' ],
        'repository3' => [ 'module6', 'module7' ],
    }
};

就像{ }返回对哈希的引用一样,[ ]返回对数组的引用。所以

for my $i (0 .. $#modulesList) {
    ... $modulesList[$i] ...
}

需要

for my $i (0 .. $#$modulesList) {
    ... $modulesList->[$i] ...
}

for my $module (@$modulesList) {
    ... $module ...
}

答案 1 :(得分:1)

这不是数组散列的散列。

$products = {
    'productName' => {
        'repository1' => ('module1', 'module2'),
        'repository2' => ('module3', 'module4', 'module5'),
        'repository3' => ('module6', 'module7')
    }
};

展平到

$products = {
    'productName' => {
        'repository1' => 'module1',
        'module2' => 'repository2',
        'module3' => 'module4',
        'module5' => 'repository3',
        'module6', 'module7',
    }
};

您需要使用arrayrefs定义数组:[]

$products = {
    'productName' => {
        'repository1' => ['module1', 'module2'],
        'repository2' => ['module3', 'module4', 'module5'],
        'repository3' => ['module6', 'module7']
    }
};

答案 2 :(得分:0)

通过哈希层次结构的递归下降与您需要在每个节点处理的内容的细节不同。一个是下行哈希的通用,另一个是你想要对数据结构做什么。

  • 首先你需要血统逻辑
  • 然后,您需要一个节点处理程序。

这大致是我的基本哈希下行器:

use Carp qw<croak>;
use Params::Util qw<_ARRAY _CODE _HASH _HASH0>;

sub  hash_descend (+@);

sub hash_descend (+@) { 
    croak ( 'Hash value or reference missing' ) 
        # I use _HASH0 here, because I don't really want to yell at the user
        # for simply providing an empty set. 
        unless _HASH0( my $h = shift )
        ;

    return unless %$h;

    # also set it up so that it can return tuples of key-paths and values
    # [ k_1, k_2, ... , k_n => v ]
    my @accum;
    my $block = _CODE( $_[0] ) ? shift : sub { push @accum, [ @_ ] };

    while ( my ( $k, $v ) = each $h ) { 
        local $_ = $v;
        $block->( @_, $k, $v );
        if ( _HASH( $v )) { 
            hash_descend( $v, $block, @_, $k );
        }
    }
    return unless @accum;
    return @accum;
}
  • 请注意,由于它是递归的,我向前声明它
  • 我还使用了新的样式原型,它将哈希和数组转换为该类型的引用。
  • 第二个参数允许回调与每个节点一起播放。
  • 我&#34; contextualize&#34;简短回调表达式的值。

一旦我完成了这项工作,我就会编写处理节点的逻辑。我想优化一些你在循环中做的不必要的逻辑,所以我提出了这个:

my $branch_arg  = $Branch ? "-r $Branch " : '';
my $command_fmt = "cvs checkout -P $branch_arg%s";

hash_descend( $products => sub { 
    return unless my $arr = _ARRAY( $_[-1] );
    foreach ( @$arr ) { 
        say sprintf( $command_fmt, $_ );
    }
});