Perl中哈希数组树的路径列表

Perl中哈希数组树的路径列表,perl,perl-data-structures,template-toolkit,Perl,Perl Data Structures,Template Toolkit,我得到了一组路径 C:\A C:\B\C D:\AB 我想把它们放在散列数组树中,这样我就可以在TT2模板中遍历它们 我的意思是: @dirs = [ { name => "C:", subs => [ { name => "A", subs => [],

我得到了一组路径

C:\A
C:\B\C
D:\AB
我想把它们放在散列数组树中,这样我就可以在TT2模板中遍历它们

我的意思是:

@dirs = [
          {
            name => "C:",
            subs => [
                      {
                        name => "A",
                        subs => [],
                      },
                      {
                        name => "B",
                        subs => [
                                  {
                                    name => "C",
                                    subs => [],
                                  }
                                ],
                      }
                    ]
          },
          { 
            name => "D:",
            subs => [
                      {
                        name => "AB",
                        subs => [],
                      }
                    ],
          }
        ]
我也知道我可能在这里做brainderp,所以我对其他方法持开放态度,唯一的要求是将路径列表转换为可以使用TT2模板工具包重建为树的内容


那个结构叫什么?我只是想到了散列数组树,但我敢打赌那是错误的。

我用一个复杂的散列结构来跟踪已经放置的节点,然后我做了这个。步骤更多,但代码更精简

while ( <> ) {
    chomp;
    my $ref = \@dirs;
    foreach my $dir ( split /\\/ ) {
        my $i = 0;
        $i++ while ( $ref->[$i] and $ref->[$i]{name} ne $dir );
        my $r = $ref->[$i] ||= { name => $dir, subs => [] };
        $ref  = $r->{subs};
    }
}
while(){
咀嚼;
我的$ref=\@dirs;
foreach my$dir(拆分/\\/){
我的$i=0;
$i++while($ref->[$i]和$ref->[$i]{name}ne$dir);
my$r=$ref->[$i]|={name=>$dir,subs=>[]};
$ref=$r->{subs};
}
}

这是一个更长但更具可读性和更舒适的解决方案。你不必(也可能不想)使用它,但也许它可以帮助(不仅仅是你)更多地了解不同的方法。它为树节点引入了一个小类,它可以使用可读的排序和字符串化方法将名称递归地添加到自身中

编辑:有关完全不同且非常简短的备选方案,请参阅我的。我把它分为两个答案,因为它们是完全不同的方法,而且这个答案已经足够长了

树类 请注意,这基本上不超过您的嵌套AoHoAoH。。。结构-添加少量糖。;)

现在,在基本准备工作(我们的对象有一个标量
名称
和一个数组ref
subs
)之后,我们来到这个答案的主要部分:递归
添加方法。请注意,从这里开始,所有内容都反映了数据结构的递归性质:

# recursively add to this tree
sub add_deeply {
    my ($self, @names)  = @_;
    my $next_name       = shift @names;

    # names empty: do nothing
    return unless defined $next_name;

    # find or create a matching tree
    my $subtree = first {$_->name eq $next_name} @{$self->subs};
    push @{$self->subs}, $subtree = Tree->new(name => $next_name, subs => [])
        unless defined $subtree;

    # recurse
    $subtree->add_deeply(@names);
}
以下两种方法并不那么重要。基本上,它们在这里是为了让输出变得漂亮:

# sort using node names
sub sort {
    my $self = shift;
    $_->sort for @{$self->subs}; # sort my children
    $self->subs([ sort {$a->name cmp $b->name} @{$self->subs} ]); # sort me
}

# stringification
use overload '""' => \&to_string;
sub to_string {
    my $self    = shift;
    my $prefix  = shift // '';

    # prepare
    my $str = $prefix . '{TREE name: "' . $self->name . '"';

    # stringify children
    if (@{$self->subs}) {
        $str .= ", children: [\n";
        $str .= $_->to_string("    $prefix") for @{$self->subs};
        $str .= "$prefix]";
    }

    # done
    return $str . "}\n";
}
如何使用这个 现在是简单的部分。只需读取输入(从这里的
\uuu DATA\uu
)和
添加深度

# done with the tree structure: now use it
package main;

# parse and add names to a tree
my $tree = Tree->new(name => 'root', subs => []);
foreach my $line (<DATA>) {
    chomp $line;
    $tree->add_deeply(split /\\/ => $line);
}

# output
$tree->sort;
print $tree;

__DATA__
C:\A
C:\B\C
D:\AB
C:\B\A
C:\B\A\C

这里有一个非常简短的方法。请注意,这只能如此简单,因为我将您的数据格式更改为完全匹配您的树结构的散列。请参阅下面的代码,将生成的结构转换为您的结构

my $tree = {root => {}};
foreach my $input (<DATA>) { chomp $input;
    my $t = $tree;
    $t = $t->{$_} //= {} for split /\\/ => $input;
}

use Data::Dumper; print Dumper $tree;

__DATA__
C:\A
C:\B\C
D:\AB
C:\B\A
C:\B\A\C
要将此数据结构转换为您的数据结构,只需使用以下代码:

sub transform {
    my $tree        = shift;
    my @children    = ();
    while (my ($name, $children) = each %$tree) {
        push @children, {
            name => $name,
            subs => [ transform($children) ],
        }
    }
    return @children;
}

my $AoH_tree = {name => 'root', subs => [transform($tree)] };

完成。:)要了解一种完全不同的方法,它有更多的优点、功能和可读性,但有更多的LOC,请参阅my。

它被简单地称为哈希数组(或AoH)。当你说“重建为树”时,你想用TT2生成什么样的输出?你想把@dirs改成$dirs,或者把最外面的括号改成括号。你确定要把每个目录都作为哈希数组吗?为什么不做
{“C:=>{'A'=>{},D:=>{…}
。这将使查找子目录变得容易得多。@user5402我只是想用模板创建一个文件夹结构,这样我就可以通过JS添加折叠。@StephenKloder我确信,因为我想保持它的排序,而上次我试图找出如何用TT2对哈希进行排序时,我就放弃了。另一件事是,我递归它的方式需要显式地使用数组。这看起来是可行的,但我忘了提到我的路径在@paths中(虽然也是在$\u0中,因为我想把它放入一个子数组中),但我似乎不知道如何将它输入。我尝试用foreach通过@path替换while,因为while刚刚挂断,但foreach只返回@path的第一个元素,至少名称=>“C:”,subs=>[](虽然subs应该包含更多内容)Nevermind工作正常,必须使用@u而不是$[0]。Perl处理变量的方式让我非常困惑。。。
my $tree = {root => {}};
foreach my $input (<DATA>) { chomp $input;
    my $t = $tree;
    $t = $t->{$_} //= {} for split /\\/ => $input;
}

use Data::Dumper; print Dumper $tree;

__DATA__
C:\A
C:\B\C
D:\AB
C:\B\A
C:\B\A\C
$VAR1 = {
          'C:' => {
                    'A' => {},
                    'B' => {
                             'A' => {
                                      'C' => {}
                                    },
                             'C' => {}
                           }
                  },
          'D:' => {
                    'AB' => {}
                  }
        };
sub transform {
    my $tree        = shift;
    my @children    = ();
    while (my ($name, $children) = each %$tree) {
        push @children, {
            name => $name,
            subs => [ transform($children) ],
        }
    }
    return @children;
}

my $AoH_tree = {name => 'root', subs => [transform($tree)] };