在一条指令中将值影响到多级哈希 [英] Affecting a value to a multilevel hash in one instruction
问题描述
我正在寻找一种更有效的方法在影响子例程=显示问题标记为'perl' =tag> perl :
$ b
#!/ usr / bin / perl
使用5.010;
使用strict;
我的@keys = qw / foo bar baz /;
my%hash =(foo => {babel =>'fish'});
影响(\%hash,42);
sub影响{
my $ ref = shift;
$ ref = $ ref-> {$ keys [$ _]} // = {} for(0 .. $#keys - 1);
$ ref-> {$ keys [$#keys]} = shift;
}
使用Data :: Dumper;
打印Dumper \%hash;
预期结果:
$ VAR1 = {
'foo'=> {
'bar'=> {
'baz'=> 42
},
'babel'=> 'fish'
}
};
我正在考虑这样的事情,但显然它不能像这样工作:
%hash {@keys} = 42;
任何想法?
如果你真的把密钥传给它,它会更有效率!
sub dive_val:lvalue {
my $ p = \转移;
$ p = \($$ p-> {$ _})for @_;
$$ p
}
my%hash;
dive_val(\%hash,qw(foo babel))='fish';
dive_val(\%hash,@keys)= 42;
这个实现有两个额外的好处。
首先,您可以使用它来查看数据结构。
print(dive_val($ hash,@keys) ,\\\
);
其次,它将autovivify其第一个参数。
my $ hash;
dive_val($ hash,@keys)= 42;
这个函数已经存在为 Data :: Diver 的 DiveVal
。
使用Dive :: Val qw(DiveVal);
DiveVal(\%hash,map \ $ _,@keys)= 42;
比较 影响
和 dive_val
:
$ b
影响
$ ref
是对散列的引用。
预循环:$ ref引用%散列
循环传递0之后:$ ref引用%{$ hash {$ key [0]}}
循环传递1:$ ref引用%{$ hash {$ key [0]} {$ key [1]}}
Post循环使用:$ ref- > {$ key [2]}
dive_val
$ p
是对标量的引用。
预循环:$ p引用$ hash
循环传递0之后:$ p引用$ hash-> {$ key [0]}
循环传递1之后:$ p引用$ hash-> {$ key [0]} {$ key [1]}
循环传递2之后:$ p引用$ hash-> {$ key [0]} {$ key [1]} {$ key [2]}
后循环使用:$$ p
dive_val
的方法是p
$ b
- 在解除引用前不需要创建哈希(不像
影响
它在前面的循环中创建它)。
- 实际上,标量根本不需要在哈希中。这意味着
dive_val
可以很容易地扩展以支持混合数组/哈希结构。
- 没有必要专门处理根目录(如果你希望接受可能未定义的参数)。
- 不需要特别处理最后一个键。
I am looking for a more effective way to write this affect
subroutine in perl:
#!/usr/bin/perl
use 5.010;
use strict;
my @keys = qw/foo bar baz/;
my %hash = ( foo => {babel => 'fish'} );
affect (\%hash, 42);
sub affect {
my $ref = shift;
$ref = $ref->{$keys[$_]} //= {} for (0.. $#keys - 1);
$ref->{$keys[$#keys]} = shift;
}
use Data::Dumper;
print Dumper \%hash;
And the expected result:
$VAR1 = {
'foo' => {
'bar' => {
'baz' => 42
},
'babel' => 'fish'
}
};
I was thinking about things like this, but obviously it can't work like this:
%hash{ @keys } = 42;
Any idea?
it would be more effective if you actually passed the keys to it! Let's make it an lvalue sub at the same time.
sub dive_val :lvalue {
my $p = \shift;
$p = \( $$p->{$_} ) for @_;
$$p
}
my %hash;
dive_val(\%hash, qw( foo babel )) = 'fish';
dive_val(\%hash, @keys) = 42;
There are two added advantages to this implementation.
First, you can use it to peek into the data structure.
print(dive_val($hash, @keys), "\n");
Second, it will autovivify its first argument.
my $hash;
dive_val($hash, @keys) = 42;
This function already exists as Data::Diver's DiveVal
.
use Dive::Val qw( DiveVal );
DiveVal(\%hash, map \$_, @keys) = 42;
Comparison of the flow of affect
and dive_val
:
affect
$ref
is a reference to a hash.Pre-loop: $ref references %hash After loop pass 0: $ref references %{ $hash{$key[0]} } After loop pass 1: $ref references %{ $hash{$key[0]}{$key[1]} } Post loop uses: $ref->{$key[2]}
dive_val
$p
is a reference to a scalar.Pre-loop: $p references $hash After loop pass 0: $p references $hash->{$key[0]} After loop pass 1: $p references $hash->{$key[0]}{$key[1]} After loop pass 2: $p references $hash->{$key[0]}{$key[1]}{$key[2]} Post loop uses: $$p
dive_val
's approach is purer.
- There's no need to create the hash before it's dereferenced (unlike
affect
which creates it in the previous loop pass). - In fact, the scalar doesn't need to be in a hash at all. This means
dive_val
could easily be extended to support mixed array/hash structures. - There's no need to treat the root specially (if you want to accept a potentially undefined argument).
- There's no need to treat the last key specially.
这篇关于在一条指令中将值影响到多级哈希的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!