pc0019 has asked for the wisdom of the Perl Monks concerning the following question:

How would I remove, say, the first 2 characters from a hash KEY? I can use the following to remove the first 2 chars from the values in the hash.

my %hash = ( '.111' => 'Aaaa', '.222' => 'Bbbb', '.333' => 'Cccc' ); $hash{$_} = substr $hash{$_}, 2 for keys %hash;

But I have no idea how to do this for the keys. Ideal output is:

print Dumper \%hash; -- -- -- -- -- -- -- -- $VAR1 = { '33' => 'Cccc', '22' => 'Bbbb', '11' => 'Aaaa' };

Thanks in advance!

Replies are listed 'Best First'.
Re: Using substr on Hash Keys
by dwm042 (Priest) on Sep 10, 2008 at 19:17 UTC
    A variant of your substring transformation can do it pretty nicely:

    #!/usr/bin/perl use warnings; use strict; my %hash = ( '.111' => 'Aaaa', '.222' => 'Bbbb', '.333' => 'Cccc' ); my %newhash = map { substr ($_, 2) => $hash{$_} } keys %hash; for ( keys %newhash ) { print "$_ => ", $newhash{$_}, "\n"; }
    The output is:

    C:\Code>perl newkeys.pl 22 => Bbbb 11 => Aaaa 33 => Cccc
    Update: For an in-place transformation, replace %newhash with %hash. e.g.

    %hash = map { substr ($_, 2) => $hash{$_} } keys %hash;
Re: Using substr on Hash Keys
by kyle (Abbot) on Sep 10, 2008 at 19:47 UTC

    TMTOWTDI:

    $hash{substr $_, 2} = delete $hash{$_} for keys %hash;

    Update: Actually, this is the same solution as jettero wrote above, but I've made it more terse.

      I was going to do something like this, but I couldn't reason out which of the delete vs the substr would happen first. It occurred to me, reading your post, that substr doesn't actually modify the string like splice modifies arrays -- so it doesn't matter.

      -Paul

        I was going to do something like this, but I couldn't reason out which of the delete vs the substr would happen first.

        Doesn't matter, unless you expect a collision between a new key and an old key. If that's the case, other solutions have the problem too. (The solution is to use another hash.)

        What does matter is that all the keys are fetched before any insertion into and deletion from the hash. And they are. for loads the entire list over which to iterate into memory before starting to loop.

        Actually, substr can modify the string if you use the fourth argument.

        Thanks everyone for the replies. I love the 'TMTOWTDI' factor about Perl, but are both methods as efficient as each other?
Re: Using substr on Hash Keys
by jettero (Monsignor) on Sep 10, 2008 at 19:03 UTC
    Pretty sure about the only way to do it (roughly) is like so:
    for my $k (keys %hash) { my $v = delete $hash{$k}; my $t = transform($k); $hash{$t} = $v; }

    UPDATE: woops. (probably a /msg would have done the trick?)
    UPDATE: no, no offense at all.

    -Paul

      Update: It's a nice solution now that it's been updated, jettero. Sorry if I offended you by posting.

      I don't see where you're assigning $v to $hash{$t} there.

Re: Using substr on Hash Keys
by poolpi (Hermit) on Sep 11, 2008 at 09:56 UTC

    See Hash::Rename
    Renaming hash's keys in place

    #!/usr/bin/perl -w use strict; use Hash::Rename; my %h = ( '.111' => 'Aaaa', '.222' => 'Bbbb', '.333' => 'Cccc' ); hash_rename %h, code => sub { s/.{2}// }; __END__ Output: $VAR1 = { '22' => 'Bbbb', '11' => 'Aaaa', '33' => 'Cccc' };

    hth,
    PooLpi

    'Ebry haffa hoe hab im tik a bush'. Jamaican proverb