3

パスの配列を取得しました

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テンプレートツールキットでツリーとして再構築できるものに変えることです.

また、その構造は何と呼ばれていますか?ハッシュ配列ツリーについて考えただけですが、それは間違っているに違いありません。

4

3 に答える 3

3

これは非常に短いアプローチです。データ形式をツリー構造に完全に一致するハッシュのハッシュに変更したため、これは非常に単純であることに注意してください。結果の構造を自分の構造に変換するには、以下のコードを参照してください。

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)] };

終わり。:)はるかに多くの砂糖、パワー、読みやすさを備えたまったく異なるアプローチについては、私の他の回答を参照してください。

于 2012-11-03T12:37:46.557 に答える
2

これはより長くなりますが、はるかに読みやすく、より快適なソリューションです。これを使用する必要はありません (おそらく使用したくないでしょう) が、(あなただけでなく) さまざまなアプローチについてさらに学ぶのに役立つ可能性があります。ツリー ノード用の小さなMooクラスを導入します。このクラスは、読み取り可能な並べ替えと文字列化メソッドを使用して、それ自体に再帰的に名前を追加できます。

編集:完全に異なる非常に短い代替案については、他の回答を参照してください。これらは完全に異なるアプローチであり、この回答はすでに十分に長いため、2つの回答に分割しました。;)

ツリークラス

これは基本的に、ネストされた AoHoAoH... 構造にすぎないことに注意してください-少し砂糖が追加されています。;)

# define a tree structure
package Tree;
use Moo; # activates strict && warnings
use List::Util 'first';

# name of this node
has name => (is => 'ro');

# array ref of children
has subs => (is => 'rw', isa => sub { die unless ref shift eq 'ARRAY' });

基本的な準備 (オブジェクトには 1 つのスカラーnameと 1 つの配列 refがありますsubs) の後、この回答の主要部分である再帰的なadd_deeply方法に行き着きます。ここから、すべてがデータ構造の再帰的な性質を反映していることに注意してください。

# 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);
}

次の 2 つの方法はそれほど重要ではありません。基本的に、それらは出力をきれいにするためにここにあります:

# 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";
}

これを使用する方法

次に簡単な部分です。__DATA__(ここから)入力を読むだけでadd_deeply

# 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

出力:

{TREE name: "root", children: [
    {TREE name: "C:", children: [
        {TREE name: "A"}
        {TREE name: "B", children: [
            {TREE name: "A", children: [
                {TREE name: "C"}
            ]}
            {TREE name: "C"}
        ]}
    ]}
    {TREE name: "D:", children: [
        {TREE name: "AB"}
    ]}
]}
于 2012-11-03T11:57:38.540 に答える
1

既に配置されたノードを追跡する複雑なハッシュ構造を使用して 1 つを作成し、次にこれを作成しました。手順は増えますが、コードはややスリムになります。

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};
    }
}
于 2012-11-02T20:00:32.237 に答える