views:

771

answers:

3

Let us say if I have a hash like this:

$data = {
    'key1' => {
                'key2' => 'value1'
              },
    'key3' => {
                'key4' => {
                            'key5' => 'value2'
                          }
              },
  };

Now, how can I replace the the key 'key5' with some other key name say 'key6'? I know how to loop through the hash & dump the values but I don't know how to replace keys or values in place. Thanks for your help.

+4  A: 

You can't replace it, but you can make a new key easily, and then delete() the old one:

$data->{key3}{key4}{key6} = $data->{key3}{key4}{key5};
delete $data->{key3}{key4}{key5};

Of course, you could make a fairly simple subroutine to do this. However, my first approach was wrong, and you would need to make a more complex approach that passes in the data structure to modify and the element to be modified, and given that you want elements several levels deep this may be difficult. Though if you don't mind a little clutter:

sub hash_replace (\%$$) {
  $_[0]->{$_[2]} = delete $_[0]->{$_[1]}; # thanks mobrule!
}

Then call it:

hash_replace %{$data->{key3}{key4}}, "key5", "key6";

Or the cool way (How better to say that we're transforming "key5" into "key6" ?):

hash_replace %{$data->{key3}{key4}}, key5 => "key6";

(Tested and works)

Chris Lutz
Any reason for a downvote? Does something not work here?
Chris Lutz
This is great, thanks for your help. This example is really good for me to understand how to approach this.
John
A: 

This 'works' but is very hard-coded.

#!/bin/perl -w
use strict;

my $data = {
    'key1' => {
        'key2' => 'value1'
    },
    'key3' => {
        'key4' => {
            'key5' => 'value2'
        }
    },
};

print "$data->{key3}->{key4}->{key5}\n";

my $save = $data->{key3}->{key4}->{key5};
delete $data->{key3}->{key4}->{key5};
$data->{key3}->{key4}->{key6} = $save;

print "$data->{key3}->{key4}->{key6}\n";

You can eliminate the '->' operators between the hash subscripts, but not the one after '$data' - as in Chris Lutz's solution.

Jonathan Leffler
I always preferred to use the fewest number of `->` that I could get away with, but I can see how it starts to get hairy quickly.
Chris Lutz
+17  A: 

The delete operator returns the value being deleted. So this

$data->{key3}{key4}{key6} = delete $data->{key3}{key4}{key5}

will do what you're looking for.

mobrule
Oh, right! I forgot about that. Off to modify my `hash_replace()`
Chris Lutz
Thank you for that. I actually didn't even know that it was possible to do it that way
John