【问题标题】:Perl data structure traversal -- reference followed keyPerl数据结构遍历——引用跟随键
【发布时间】:2011-10-04 06:39:26
【问题描述】:

结果: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 的调用。
  • 我不知道这个任务的更好的模块。
  • 我可以内联的快速代码 sn-p
  • 我自己的模块/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);

大师?

【问题讨论】:

  • 你想要什么输出?看起来你想要三列输出,但前两列你想要什么?
  • 我要插入的键——基本名称、哈希、完整路径。我看到的不是键,而是由基本名称和哈希键重新定义的结构。
  • 您好,我注意到您参与了“医疗保健 IT”堆栈交换,并认为您可能对此提案感兴趣 -> Healthcare Industry

标签: perl data-structures traversal


【解决方案1】:

编辑:根据我的更好判断,我会尝试再次回答这个问题。

这是一种打印所需内容的简单方法。使用 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;

【讨论】:

  • 示例代码不会神奇地改变,但我会发现它在其他情况下很有用。为 2 深度编写多个 for 循环并不是什么大问题,但我正在考虑更大的结构,并且我定期编写这些循环。示例代码仅作为示例,而不是“解决此目录列表问题”。此外,“File::Find”会很笨拙——该列表上已经发生了很多解析工作。
  • 所以,你问的问题很糟糕,然后对那些试图提供帮助的人投了反对票。太好了。
  • 你添加了什么?它比一个小时的答案更难阅读。它假定改变了我的输入源。它与我已经澄清的地方相矛盾,“我想要一段 N 级兼容的代码”告诉我我不需要它。我认为这是一个答案对问题没有帮助的明显案例。承认和澄清(在你回答之前)一个问得不好的问题对你提供的帮助没有帮助。
【解决方案2】:
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。)

其他一些清理工作:

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 表示干净的代码,但不是一个可接受的答案,因为对于 N 级结构,我将不得不写出所有这些 for 循环(这就是我开始的内容)。
  • @Jeff Ferland,您没有询问 N 级结构。不过,它可能不会改变答案。除非你想要一些通用的东西(比如 Data::Dumper),否则你需要嵌套循环。你只是不知道如何干净地做到这一点。提示:使用潜艇!
  • 公平地说,我对此并不明确,但我确实试图用我可能的解决方案评论来暗示它。我现在要明确地改变我的问题。
  • 我想澄清一下——+1 以获得干净的第一个循环。它与我的相似,值得付出一些努力。 “没有弄清楚如何干净地做到这一点”和“提示:使用 subs”(我在示例中这样做)感觉非常屈尊,以不同的风格重写整个代码也是如此。你对评论的编辑让我想撤回我的投票(我没有),并可能踢你的小腿。
  • @Jeff Ferland,我以为你会把你的问题改成关于任意深度结构的问题?
猜你喜欢
  • 1970-01-01
  • 2012-08-25
  • 1970-01-01
  • 1970-01-01
  • 2015-06-30
  • 1970-01-01
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
相关资源
最近更新 更多