Transform hash key?

Discussion in 'Perl Misc' started by MSG, Jan 31, 2006.

  1. MSG

    MSG Guest

    I'd like to change a hash's keys from all lower cases to upper
    The code below works but it just doesn't *feel* right with %temp.
    Can it be done in a short one line of code, like how map() works
    on arrays?

    #!/usr/bin/perl

    use strict;
    use warnings;

    my %h = ( a=>"1x", c=>"2y", b=>"3z" );
    my %temp;
    foreach my $k (keys %h){
    $temp{uc $k} = $h{$k};
    }
    %h = %temp; # %h = (A=>"1x", c=>"2y", B=>"3z")
    MSG, Jan 31, 2006
    #1
    1. Advertising

  2. "MSG" <> wrote in news:1138685184.204561.68790
    @z14g2000cwz.googlegroups.com:

    > I'd like to change a hash's keys from all lower cases to upper
    > The code below works but it just doesn't *feel* right with %temp.
    > Can it be done in a short one line of code, like how map() works
    > on arrays?
    >
    > #!/usr/bin/perl
    >
    > use strict;
    > use warnings;
    >
    > my %h = ( a=>"1x", c=>"2y", b=>"3z" );
    > my %temp;
    > foreach my $k (keys %h){
    > $temp{uc $k} = $h{$k};
    > }
    > %h = %temp; # %h = (A=>"1x", c=>"2y", B=>"3z")


    #!/usr/bin/perl

    use warnings;
    use strict;

    my %h = (a => "1x", c => "2y", b => "3z");
    %h = map { uc $_ => $h{$_} } keys %h;

    use Data::Dumper;
    print Dumper \%h;

    --
    A. Sinan Unur <>
    (reverse each component and remove .invalid for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
    A. Sinan Unur, Jan 31, 2006
    #2
    1. Advertising

  3. MSG

    MSG Guest

    A. Sinan Unur wrote:
    > "MSG" <> wrote in news:1138685184.204561.68790
    > @z14g2000cwz.googlegroups.com:
    >
    > > I'd like to change a hash's keys from all lower cases to upper
    > > The code below works but it just doesn't *feel* right with %temp.
    > > Can it be done in a short one line of code, like how map() works
    > > on arrays?
    > >
    > > #!/usr/bin/perl
    > >
    > > use strict;
    > > use warnings;
    > >
    > > my %h = ( a=>"1x", c=>"2y", b=>"3z" );
    > > my %temp;
    > > foreach my $k (keys %h){
    > > $temp{uc $k} = $h{$k};
    > > }
    > > %h = %temp; # %h = (A=>"1x", c=>"2y", B=>"3z")

    >
    > #!/usr/bin/perl
    >
    > use warnings;
    > use strict;
    >
    > my %h = (a => "1x", c => "2y", b => "3z");
    > %h = map { uc $_ => $h{$_} } keys %h;
    >
    > use Data::Dumper;
    > print Dumper \%h;
    >
    > --
    > A. Sinan Unur <>
    > (reverse each component and remove .invalid for email address)
    >
    > comp.lang.perl.misc guidelines on the WWW:
    > http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html


    Thanks! It is exactly what I am looking for!
    MSG, Jan 31, 2006
    #3
  4. "MSG" <> wrote in news:1138687376.623849.42190
    @g47g2000cwa.googlegroups.com:

    > A. Sinan Unur wrote:
    >> "MSG" <> wrote in news:1138685184.204561.68790
    >> @z14g2000cwz.googlegroups.com:
    >>
    >> > I'd like to change a hash's keys from all lower cases to upper

    ....
    >> my %h = (a => "1x", c => "2y", b => "3z");
    >> %h = map { uc $_ => $h{$_} } keys %h;
    >>
    >> use Data::Dumper;
    >> print Dumper \%h;
    >>
    >> --
    >> A. Sinan Unur <>
    >> (reverse each component and remove .invalid for email address)
    >>
    >> comp.lang.perl.misc guidelines on the WWW:
    >> http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html

    >
    > Thanks! It is exactly what I am looking for!


    You are welcome. Glad to be of help.

    However, I presume, you were not looking for my signature. Please trim
    the quoted material in your replies, and don't quote signatures.

    Sinan

    --
    A. Sinan Unur <>
    (reverse each component and remove .invalid for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
    A. Sinan Unur, Jan 31, 2006
    #4
  5. MSG

    Uri Guttman Guest

    >>>>> "ASU" == A Sinan Unur <> writes:

    ASU> "MSG" <> wrote in news:1138685184.204561.68790
    ASU> @z14g2000cwz.googlegroups.com:

    >> I'd like to change a hash's keys from all lower cases to upper
    >> The code below works but it just doesn't *feel* right with %temp.
    >> Can it be done in a short one line of code, like how map() works
    >> on arrays?


    ASU> my %h = (a => "1x", c => "2y", b => "3z");
    ASU> %h = map { uc $_ => $h{$_} } keys %h;

    i would use the for modifier (untested)

    $h{uc $_} = delete $h{$_} for keys %h;

    i expect it to be faster but only benchmark knows for sure!

    uri

    --
    Uri Guttman ------ -------- http://www.stemsystems.com
    --Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
    Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
    Uri Guttman, Jan 31, 2006
    #5
  6. Uri Guttman <> wrote in news::

    >>>>>> "ASU" == A Sinan Unur <> writes:

    >
    > ASU> "MSG" <> wrote in news:1138685184.204561.68790
    > ASU> @z14g2000cwz.googlegroups.com:
    >
    > >> I'd like to change a hash's keys from all lower cases to upper
    > >> The code below works but it just doesn't *feel* right with %temp.
    > >> Can it be done in a short one line of code, like how map() works
    > >> on arrays?

    >
    > ASU> my %h = (a => "1x", c => "2y", b => "3z");
    > ASU> %h = map { uc $_ => $h{$_} } keys %h;
    >
    > i would use the for modifier (untested)
    >
    > $h{uc $_} = delete $h{$_} for keys %h;
    >
    > i expect it to be faster but only benchmark knows for sure!


    Hmmm ... yes, this is neat.

    #!/usr/bin/perl

    use warnings;
    use strict;

    use Benchmark qw( cmpthese );

    my %h = map { $_ => 1 } ('aaa' .. 'zzz');

    cmpthese -1, {
    map => sub { %h = map { uc $_ => $h{$_} } keys %h },
    for => sub { $h{uc $_} = delete $h{$_} for keys %h; },
    };

    D:\Home\asu1\UseNet\clpmisc> s.pl
    Rate map for
    map 12.4/s -- -60%
    for 31.5/s 153% --

    So the for loop takes about 1/3 of the time the map takes, and
    this ratio remains roughly constant when the number of keys is
    increased.

    Nice.
    --
    A. Sinan Unur <>
    (reverse each component and remove .invalid for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
    A. Sinan Unur, Jan 31, 2006
    #6
  7. MSG

    DJ Stunks Guest

    A. Sinan Unur wrote:
    >
    > #!/usr/bin/perl
    >
    > use warnings;
    > use strict;
    >
    > use Benchmark qw( cmpthese );
    >
    > my %h = map { $_ => 1 } ('aaa' .. 'zzz');
    >
    > cmpthese -1, {
    > map => sub { %h = map { uc $_ => $h{$_} } keys %h },
    > for => sub { $h{uc $_} = delete $h{$_} for keys %h; },
    > };
    >
    > D:\Home\asu1\UseNet\clpmisc> s.pl
    > Rate map for
    > map 12.4/s -- -60%
    > for 31.5/s 153% --
    >
    > So the for loop takes about 1/3 of the time the map takes, and
    > this ratio remains roughly constant when the number of keys is
    > increased.
    >
    > Nice.


    Would it be possible to alias the keys and edit in-place? It would be
    easy to do so with the values, but I'm not sure about the keys.

    Just wondering.

    Tks.
    -jp
    DJ Stunks, Jan 31, 2006
    #7
  8. MSG

    Uri Guttman Guest

    >>>>> "ASU" == A Sinan Unur <> writes:

    ASU> my %h = map { $_ => 1 } ('aaa' .. 'zzz');

    ASU> cmpthese -1, {
    ASU> map => sub { %h = map { uc $_ => $h{$_} } keys %h },
    ASU> for => sub { $h{uc $_} = delete $h{$_} for keys %h; },
    ASU> };

    this benchmark has a common problem in that you don't set up the hash
    the same way for each run. the first time you call either sub, the hash
    will have only upper case keys. now i doubt that uc will be faster or
    slower given any mix of input case but it still is wrong. if the
    transform were something whose speed was data dependent, this benchmark
    would be very bogus.

    the map one could be fixed just by assigning it to a different hash. the
    for one would need a fresh hash each time as it modifies it in place. so
    you would need to do the same work for each one and my best idea would
    be to copy the %h to %h2 inside each sub and use that as the input (and
    you can use it for the output of the map. also choosing a different
    output hash for the map could affect speed as well.

    this is just a small lesson on the difficulty of properly benchmarking
    apples and apples.

    uri

    --
    Uri Guttman ------ -------- http://www.stemsystems.com
    --Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
    Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
    Uri Guttman, Jan 31, 2006
    #8
  9. MSG

    Uri Guttman Guest

    >>>>> "DS" == DJ Stunks <> writes:

    >>
    >> my %h = map { $_ => 1 } ('aaa' .. 'zzz');
    >>
    >> cmpthese -1, {
    >> map => sub { %h = map { uc $_ => $h{$_} } keys %h },
    >> for => sub { $h{uc $_} = delete $h{$_} for keys %h; },
    >> };
    >>
    >> D:\Home\asu1\UseNet\clpmisc> s.pl
    >> Rate map for
    >> map 12.4/s -- -60%
    >> for 31.5/s 153% --


    >> Nice.


    DS> Would it be possible to alias the keys and edit in-place? It would be
    DS> easy to do so with the values, but I'm not sure about the keys.

    the values function in recent perls returns aliases to the values (which
    are normal perl scalars) of the hash so you can directly mung them. but
    the keys aren't normal perl values and so you can't take a reference or
    alias to them. you have to deal with them indirectly via the hash's
    interface which is what those two solutions do.

    uri

    --
    Uri Guttman ------ -------- http://www.stemsystems.com
    --Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
    Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
    Uri Guttman, Jan 31, 2006
    #9
  10. Uri Guttman <> wrote in
    news::

    >>>>>> "ASU" == A Sinan Unur <> writes:

    >
    > ASU> my %h = map { $_ => 1 } ('aaa' .. 'zzz');
    >
    > ASU> cmpthese -1, {
    > ASU> map => sub { %h = map { uc $_ => $h{$_} } keys %h },
    > ASU> for => sub { $h{uc $_} = delete $h{$_} for keys %h; },
    > ASU> };
    >
    > this benchmark has a common problem in that you don't set up the hash
    > the same way for each run.


    I actually thought about this before posting.

    > the first time you call either sub, the hash will have only
    > upper case keys. now i doubt that uc will be faster or slower
    > given any mix of input case


    Which is why I decided not worry about it (in this case).

    > but it still is wrong.


    I am not sure it is that wrong.

    > if the transform were something whose speed was data dependent,
    > this benchmark would be very bogus.


    Absolutely.

    > the map one could be fixed just by assigning it to a different hash.
    > the for one would need a fresh hash each time as it modifies it in
    > place. so you would need to do the same work for each one and my best
    > idea would be to copy the %h to %h2 inside each sub and use that as
    > the input (and you can use it for the output of the map. also choosing
    > a different output hash for the map could affect speed as well.
    >
    > this is just a small lesson on the difficulty of properly benchmarking
    > apples and apples.


    Do you meam I should use:

    #!/usr/bin/perl

    use warnings;
    use strict;

    use Benchmark qw( cmpthese );

    my %h = map { $_ => 1 } ('aaa' .. 'zzz');

    cmpthese -1, {
    map => sub { my %h2 = %h; %h2 = map { uc $_ => $h{$_} } keys %h },
    for => sub { my %h2 = %h; $h2{uc $_} = delete $h2{$_} for keys %h2; },
    };
    __END__

    D:\Home\asu1\UseNet\clpmisc> s.pl
    Rate map for
    map 7.31/s -- -39%
    for 12.0/s 64% --

    Or, should I omit the my %h2 = %h in the 'map' version?

    D:\Home\asu1\UseNet\clpmisc> s.pl
    Rate for map
    for 12.1/s -- -3%
    map 12.4/s 3% --

    I don't think the latter version is fair to 'for' though.

    Sinan

    --
    A. Sinan Unur <>
    (reverse each component and remove .invalid for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
    A. Sinan Unur, Jan 31, 2006
    #10
  11. MSG

    Uri Guttman Guest

    >>>>> "ASU" == A Sinan Unur <> writes:

    ASU> Uri Guttman <> wrote in
    ASU> news::

    >> this benchmark has a common problem in that you don't set up the hash
    >> the same way for each run.


    ASU> I actually thought about this before posting.

    >> the first time you call either sub, the hash will have only
    >> upper case keys. now i doubt that uc will be faster or slower
    >> given any mix of input case


    ASU> Which is why I decided not worry about it (in this case).

    still not a good idea to not deal with it. it may have worked ok for
    this case but it could lead you or someone reading this to make similar
    broken benchmarks.

    >> the map one could be fixed just by assigning it to a different hash.
    >> the for one would need a fresh hash each time as it modifies it in
    >> place. so you would need to do the same work for each one and my best
    >> idea would be to copy the %h to %h2 inside each sub and use that as
    >> the input (and you can use it for the output of the map. also choosing
    >> a different output hash for the map could affect speed as well.


    ASU> Do you meam I should use:

    ASU> #!/usr/bin/perl

    ASU> use warnings;
    ASU> use strict;

    ASU> use Benchmark qw( cmpthese );

    ASU> my %h = map { $_ => 1 } ('aaa' .. 'zzz');

    ASU> cmpthese -1, {
    ASU> map => sub { my %h2 = %h; %h2 = map { uc $_ => $h{$_} } keys %h },
    ASU> for => sub { my %h2 = %h; $h2{uc $_} = delete $h2{$_} for keys %h2; },
    ASU> };
    ASU> __END__

    ASU> D:\Home\asu1\UseNet\clpmisc> s.pl
    ASU> Rate map for
    ASU> map 7.31/s -- -39%
    ASU> for 12.0/s 64% --

    that would be a better and more truthful benchmark. and you should add a
    control case which just does the hash copy so you could subtract that
    time and get a more accurate comparison of the real code under test.

    ASU> D:\Home\asu1\UseNet\clpmisc> s.pl
    ASU> Rate for map
    ASU> for 12.1/s -- -3%
    ASU> map 12.4/s 3% --

    ASU> I don't think the latter version is fair to 'for' though.

    no, that is unfair.

    uri

    --
    Uri Guttman ------ -------- http://www.stemsystems.com
    --Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
    Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
    Uri Guttman, Jan 31, 2006
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. M P
    Replies:
    1
    Views:
    465
  2. rp
    Replies:
    1
    Views:
    517
    red floyd
    Nov 10, 2011
  3. Une bévue
    Replies:
    5
    Views:
    149
    Une bévue
    Aug 10, 2006
  4. Old Echo
    Replies:
    7
    Views:
    137
    Trans
    Jan 2, 2008
  5. Antonio Quinonez
    Replies:
    2
    Views:
    167
    Antonio Quinonez
    Aug 14, 2003
Loading...

Share This Page