Veltro has asked for the wisdom of the Perl Monks concerning the following question:
Once upon a time...
I wrote a piece of code that did not exactly do what I wanted. Consider the following:
use strict ; use warnings ; use Data::Dumper ; my %hash_origin = ( 'key1' => 1, 'key2' => 1, 'key3' => 1 ) ; my @keys = qw( key1 key1 key2 key2 key2 ) ; my %hash ; foreach ( @keys ) { my $key = $_ ; $hash{ $key } += $hash_origin{ $key } ; } print Dumper( \%hash ) ; __END__ $VAR1 = { 'key1' => 2, 'key2' => 3 };
What was missing was the key 'key3' in the result because the result had to match the original hash! So I went back into solitude and pondered the following solution:
my %hash2 ; my @keys_origin = keys %hash_origin ; @hash2{@keys_origin} = (0) x @keys_origin ; foreach ( @keys ) { my $key = $_ ; if ( exists $hash2{ $key } ) { $hash2{ $key } += $hash_origin{ $key } ; } } print Dumper( \%hash2 ) ; __END__ $VAR1 = { 'key3' => 0, 'key2' => 3, 'key1' => 2 };
Awesome! Was it not until last Thursday that I knew I had found the solution for these kind of things, but then this pesky little code had sprung from my hands:
my %hash3_origin = ( 'key1' => [1, 2], 'key2' => [3, 4], 'key3' => [5, + 6] ) ; my @keys3_0 = qw( key1 key1 key2 key2 key2 ) ; my @keys3_1 = qw( key2 key3 key3 key3 key3 ) ; my %hash3 ; my @keys3_origin = keys %hash3_origin ; @hash3{@keys3_origin} = ([0, 0]) x @keys3_origin ; foreach ( @keys3_0 ) { my $key = $_ ; $hash3{ $key }->[0] += $hash3_origin{ $key }->[0] ; } foreach ( @keys3_1 ) { my $key = $_ ; $hash3{ $key }->[1] += $hash3_origin{ $key }->[1] ; } print Dumper( \%hash3 ) ; __END__ $VAR1 = { 'key3' => [ 11, 28 ], 'key1' => $VAR1->{'key3'}, 'key2' => $VAR1->{'key3'} };
As yo can see in the result this is not what is intended. So I went back into solitude. (And I am not kidding, my gf was calling me the other day: Can you stop doing your Perl Monkey stuff!!!). But nevertheless, I found this (and here it comes) ugly solution by replacing this line:
@hash3{@keys3_origin} = ([0, 0]) x @keys3_origin ;
into:
@hash3{@keys3_origin} = map [($_) x 2], (0) x @keys3_origin ;
But but but... why can't I just:
@hash3{@keys3_origin} = ((0, 0)) x @keys3_origin ; or @hash3{@keys3_origin} = (@{[0, 0]}) x @keys3_origin ;
Because scalar says: There is no equivalent operator to force an expression to be interpolated in list context because in practice, this is never needed. If you really wanted to do so, however, you could use the construction @{[ (some expression) ]} , but usually a simple (some expression) suffices.
Never needed? Well, there is only one way to say this: I need that right here! I want x in list-list context! And it seems there is no way to do it!
Dear Monks: Is there any way to do this more beautifully? I just can't grasp the ugliness of the solution that I have found! I seek for a nice to read one line instruction similar to the one that I already found.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Best way to initialize hash x repetition array?
by ikegami (Patriarch) on Jun 29, 2018 at 20:38 UTC | |
by Veltro (Hermit) on Jun 29, 2018 at 21:49 UTC | |
by BrowserUk (Patriarch) on Jun 30, 2018 at 04:28 UTC | |
by Veltro (Hermit) on Jun 30, 2018 at 07:28 UTC | |
by ikegami (Patriarch) on Jun 30, 2018 at 18:07 UTC | |
by ikegami (Patriarch) on Jun 30, 2018 at 18:06 UTC |