配列のリストからツリー状のデータ構造に変換する必要があります。データの処理を開始する前にツリーの深さを知っていますが、コードを再利用できるように柔軟性を維持したいと考えています。
そこで、(Moose ベースのモジュール内から) その場で subref を生成して、配列からツリーに移動するというアイデアにたどり着きました。このように(単純化された方法で):
use Data::Dump qw/dump/;
sub create_tree_builder {
my $depth = shift;
return eval join '', 'sub { $_[0]->{$_[',
join(']}->{$_[', (1..$depth)),
']} = $_[', $depth + 1 , '] }';
}
my $s = create_tree_builder(5);
my $tree = {};
$s->($tree, qw/one two three four five/, 'a value');
print dump $tree;
# prints
# {
# one => { two => { three => { four => { five => "a value" } } } },
# }
これは私に世界を切り開き、パラメトリックに生成された文字列をあらゆる場所で関数に評価するこのプロセスのクールな用途を見つけています(明らかに、問題を探すための解決策です)。
しかし、それは少し気持ちが良すぎて、ほとんど真実ではありません。
この慣行に対するアドバイスはありますか?または改善のための提案?
任意の入力を評価することが最も安全ではない可能性があることははっきりとわかりますが、他に何がありますか?
ファローアップ
すべての答えをありがとう。私は amon のコードを使用して、次のように少しベンチマークしました。
use Benchmark qw(:all) ;
$\ = "\n";
sub create_tree_builder {
my $depth = shift;
return eval join '', 'sub { $_[0]->{$_[',
join(']}->{$_[', (1..$depth)),
']} = $_[', $depth + 1 , '] }';
}
my $s = create_tree_builder(5);
$t = sub {
$_[0] //= {};
my ($tree, @keys) = @_;
my $value = pop @keys;
$tree = $tree->{shift @keys} //= {} while @keys > 1;
$tree->{$keys[0]} = $value;
};
cmpthese(900000, {
'eval' => sub { $s->($tree, qw/one two three four five/, 'a value') },
'build' => sub { $t->($tree, qw/one two three four five/, 'a value') },
});
結果は、評価されたファクトリではなく、ツリーの構築に明らかに有利です。
Rate build eval
build 326087/s -- -79%
eval 1525424/s 368% --
私は以前にそれを行うことができたことを認めます。(同じ要素を何度も割り当てるのではなく) より多くのランダム ツリーを試してみますが、結果が異なる理由はわかりません。
助けてくれてありがとう。