Perl数据结构遍历 - 引用跟随键

时间:2011-10-03 15:23:10

标签: perl data-structures traversal

结果:许多行HASH(0x1948958) ARRAY(0x1978250) ./directory/filename

期望的结果:[Key of first hash] [Key of second hash] ./directory/filename #(elements of array, currently working)

Catch:应该进行N级结构,因此我尝试使用Data :: Walk。

当我走结构时,我真正想要做的是引用正在使用的密钥。有点像Data :: Dumper但是以制表符分隔而不是代码格式。我认为可能的解决方案(按优先顺序排列)是:

  • 有人打电话给我忽略的Data :: Walk。
  • 这项任务的一个更好的模块,我不知道。
  • 我可以内联的快速代码段
  • 我自己的Data :: Walk / Data :: Dumper(大皱眉)模块/分叉,它将添加此功能。

use strict;
use File::Basename;
use Data::Walk;

my $files;
while (<>) {
        chomp;
        #ls -l output in a file; referencing filename from it (8th column)
        my @line = split(/ /, $_, 8);
        #fileparse exported by File::Basename
        my ($name,$path) = fileparse($line[7]);
        open (my $fh, '<', $path . $name);
        my $sha = Digest::SHA->new('sha1');
        $sha->addfile($fh);
        #finding files by basename, then unique hash, then however many places it is stored.
        #question not why I don't use the hash as the first field.

        #basename    digest    path
        push(@{$files->{$name}->{$sha->hexdigest}}, $path . $name);
}

my @val;
sub walkit {
        $val[$Data::Walk::depth - 1] =  $_;
        if ($Data::Walk::depth == 3) {
                print join("\t", @val), "\n";
        }
}

&walk (\&walkit, %$files);

大师?

2 个答案:

答案 0 :(得分:3)

for my $name (keys(%$files)) {
   for my $digest (keys(%{$files->{$name}})) {
      my @qfns = @{ $files->{$name}{$digest} };
      if (@qfns > 1) {
         say "For $name and $digest,";
         say "   $_" for @qfns;
      }
   }
}

(我假设您正在寻找重复项,因此当只有一个路径与名称摘要组合相关时,我什么都不打印。如果您想要打印所有内容,可以删除if。)< / p>

其他一些清理:

use strict;
use warnings;
use 5.010;

use Digest::SHA    qw( );
use File::Basename qw( basename );

sub calc_digest {
   my ($qfn) = @_;
   open(my $fh, '<', $qfn) or die $!;
   my $sha = Digest::SHA->new('sha1');
   $sha->addfile($fh);
   return $sha->hexdigest();
}

my $files;
while (<>) {
   my $qfn = (split)[7];
   my $name = basename($path);
   my $digest = calc_digest($qfn);
   push @{ $files->{$name}{$digest} }, $qfn;
}

(“qfn”代表“限定文件名”,表示文件的路径,而不是$path包含的内容。即使$line[7]包含它,您也反复构建路径。)

答案 1 :(得分:3)

修改:反对我更好的判断,我会再次尝试回答这个问题。

这是一种打印您想要的简单方法。使用Data :: Walk是不可行的,因为当你在哈希中时你没有键上下文(你只是得到一个指向容器的指针。)

此功能适用于有些复杂的结构。当然,如果你把一个函数引用或者那些东西放在那里,它就不会给出正确的输出。

use strict;
use warnings;

my $res;
sub walk {
    my ($item, $path) = @_;
    if (ref $item eq 'ARRAY') {
        foreach (@$item) {
            walk($_, $path);
        }
    } elsif (ref $item eq 'HASH') {
        foreach (keys %$item) {
            push @$path, $_;
            walk($item->{$_}, $path);
            pop @$path;
        }
    } else {
        print join('-', @$path, $item), "\n";
    }
}

my $struct = {
    a => {
            a1 => { a11 => [ 1, 2, 3 ] },
            a2 => { a22 => [5, 6, 7] }
    },
    b => { b1 => [ 99 ], },
    c => [ 100, 101, ],
    d => [ 101, { d2 => { d3 => [200, 210] }, }, ],
};

walk $struct;