[perl] 複雑なデータ構造のvalue を一気に書き換える方法
ハッシュと配列の参照が入り交じったような複雑なデータ構造の、全value を均等に加工したかったので次の様にしてみました。
use strict; use Perl6::Say; use Data::Dumper; sub cook_hash { my ( $rh, $rf_cook ) = @_; my %tmp; for ( keys %$rh ) { if ( ref $rh->{$_} eq '' ) { $tmp{$_} = $rf_cook->( $rh->{$_} ); # ここで加工を実行 } elsif ( ref $rh->{$_} eq 'HASH' ) { $tmp{$_} = cook_hash( $rh->{$_}, $rf_cook ); } elsif ( ref $rh->{$_} eq 'ARRAY' ) { $tmp{$_} = cook_array( $rh->{$_}, $rf_cook ); } else { # SCALAR, CODE, REF, GLOB, Objects は加工しないで元の値を採用 $tmp{$_} = $rh->{$_}; } } return \%tmp; } sub cook_array { my ( $ra, $rf_cook ) = @_; my @tmp; for (@$ra) { if ( ref $_ eq '' ) { push @tmp, $rf_cook->($_); # ここで加工を実行 } elsif ( ref $_ eq 'HASH' ) { push @tmp, cook_hash( $_, $rf_cook ); } elsif ( ref $_ eq 'ARRAY' ) { push @tmp, cook_array( $_, $rf_cook ); } else { push @tmp, $_; } } return \@tmp; } my $rh_testdata = { 'a' => 1, 'b' => { 'aa' => 1, 'ab' => [ 1, 2, 3, \'test', 5 ], 'ac' => 3, }, 'c' => 3, 'd' => 4, 'e' => 5, }; # 実行 say Dumper cook_hash( $rh_testdata, sub { 'cooked' . shift } );
cook_hash とcook_array がそれぞれ再帰になっており、かつお互いに呼び合うような構造でもあり、ちょっと面白いなと思いました。
実行結果は次の通り。
perl test.pl $VAR1 = { 'e' => 'cooked5', 'c' => 'cooked3', 'a' => 'cooked1', 'b' => { 'ab' => [ 'cooked1', 'cooked2', 'cooked3', \'test', 'cooked5' ], 'ac' => 'cooked3', 'aa' => 'cooked1' }, 'd' => 'cooked4' };
意図したようにvalue が処理されています。ホクホク。
すでに似たモジュールがある気が激しくしています!
ご存知でしたらぜひ教えてくださいませ。