in reply to replace a key with its value

This is slightly more complicated than your average hash walker, since we need to know how to modify the parent. This solution passes around an $extra hash with information on how to update the parent. $extra is expected to have keys parent and key. Based on the ref of parent, we update it as a hash or an array. We could make this a bit cleaner by a closure as the extra argument, and we call the closure when we find a match.
#!/usr/bin/perl -w use strict; use Data::Dumper; use Test::More tests => 1; my $element = { 'check' => { 'field' => 'OLK_BO_BK_TYPE' }, 'type' => 'case', 'case' => [ { 'value' => '1', 'resultset' => 'BROKER' }, { 'value' => '3', 'resultset' => { 'field' => 'OLK_BO_BK_DESC' }, }, ] }; my $expected = { 'check' => 'OLK_BO_BK_TYPE', 'type' => 'case', 'case' => [ { 'value' => '1', 'resultset' => 'BROKER' }, { 'value' => '3', 'resultset' => 'OLK_BO_BK_DESC', }, ] }; hash_walk($element); is_deeply( $element, $expected, "hash_walk worked as expected"); sub hash_walk { my ( $element, $extra ) = @_; my ( $parent, $pkey ); if ($extra) { $parent = $extra->{parent}; $pkey = $extra->{key}; } if ( ref($element) =~ /HASH/ ) { foreach my $key ( keys %$element ) { if ( $key =~ /field/ ) { if ( ref($parent) eq 'HASH' ) { $parent->{$pkey} = $element->{$key}; } elsif ( ref( $parent eq 'ARRAY' ) ) { $parent->[$pkey] = $element->{$key}; } else { warn("I don't know what to do with field in parent +[$parent]" ); } } else { hash_walk( $element->{$key}, { parent => $element, key => $key } ); } } } elsif ( ref($element) =~ /ARRAY/ ) { my $upper = @$element - 1; foreach my $i ( 0 .. $upper ) { my $index = $element->[$i]; hash_walk( $index, { parent => $element, key => $i } ); } }

Replies are listed 'Best First'.
Re^2: replace a key with its value
by spazm (Monk) on Jul 08, 2009 at 19:35 UTC
    In this version I pass around a closure code reference to get evaluated when we find matching fields.

    I find this much prettier, since we aren't duplicating the ref code and it simplifies the matching code.

    #!/usr/bin/perl -w use strict; use Data::Dumper; use Test::More tests => 1; my $element = { 'check' => { 'field' => 'OLK_BO_BK_TYPE' }, 'type' => 'case', 'case' => [ { 'value' => '1', 'resultset' => 'BROKER' }, { 'value' => '3', 'resultset' => { 'field' => 'OLK_BO_BK_DESC' }, }, ] }; my $expected = { 'check' => 'OLK_BO_BK_TYPE', 'type' => 'case', 'case' => [ { 'value' => '1', 'resultset' => 'BROKER' }, { 'value' => '3', 'resultset' => 'OLK_BO_BK_DESC', }, ] }; hash_walk($element); is_deeply( $element, $expected, "hash_walk worked as expected"); sub hash_walk { my ( $element, $update ) = @_; if ( ref($element) =~ /HASH/ ) { foreach my $key ( keys %$element ) { my $value = $element->{$key}; if ( $key =~ /field/ ) { $update->( $value); } else { hash_walk( $value, sub { $element->{$key} = shift } ); } } } elsif ( ref($element) =~ /ARRAY/ ) { my $upper = @$element - 1; foreach my $i ( 0 .. $upper ) { my $index = $element->[$i]; hash_walk( $index, sub { $element->[$i] = shift } ); } } }
Re^2: replace a key with its value
by micmac (Acolyte) on Jul 08, 2009 at 19:56 UTC
    Thank-you very, very much. The parent/closure ideas are excellent and I would never have thought of that.
    Much obliged,
    -micmac
    tx to moritz also for the helpful tidbit.