Re^6: Combinations of lists, etc
by tel2 (Pilgrim) on Oct 07, 2019 at 06:59 UTC
|
Thanks LanX.
I'm trying to modify your code to handle update #2 in my original post, i.e. this line:
@hash{@keys} = ('value2') x @keys
This test seems to work as I want it to:
perl -MData::Dump -e '@hash{(key1,key2)} = ({a=>1, b=>2},{a=>1,b=>2});
+dd \%hash'
{ key1 => { a => 1, b => 2 }, key2 => { a => 1, b => 2 } }
But when I try to multiply the values out, it doesn't:
perl -MData::Dump -e '@hash{(key1,key2)} = ({a=>1, b=>2}) x 2;dd \%has
+h'
do {
my $a = { key1 => { a => 1, b => 2 }, key2 => 'fix' };
$a->{key2} = $a->{key1};
$a;
}
And the debugger didn't shed any light for me, either.
What am I doing wrong, please? And what's that 'fix' thing about? | [reply] [d/l] [select] |
|
|
Further to LanX's reply: Consider the two statements
@ra = ({a=>1, b=>2}, {a=>1, b=>2});
and
@ra = ({a=>1, b=>2}) x 2;
In the first, two different anonymous array references are being constructed. In the second, a single anonymous array reference is constructed and then repeated twice.
c:\@Work\Perl\monks\tel2>perl -wMstrict -MData::Dump -le
"my @ra = ({a=>1, b=>2}, {a=>1, b=>2});
print qq{@ra};
;;
@ra = ({a=>1, b=>2}) x 2;
print qq{@ra};
"
HASH(0x1555cdc) HASH(0x1555e50)
HASH(0x1555e20) HASH(0x1555e20)
In
c:\@Work\Perl\monks\tel2>perl -wMstrict -MData::Dump -le
"my %hash;
;;
@hash{ qw(key1 key2) } = ({a=>1, b=>2},{a=>1,b=>2});
dd \%hash;
;;
@hash{ qw(key1 key2) } = ({a=>1, b=>2}) x 2;
dd \%hash;
"
{ key1 => { a => 1, b => 2 }, key2 => { a => 1, b => 2 } }
do {
my $a = { key1 => { a => 1, b => 2 }, key2 => 'fix' };
$a->{key2} = $a->{key1};
$a;
}
the do { ... } business with the 'fix' in the second dd instance just reflects the fact that a hash reference $a is built that needs to have its 'key2' key "fixed" later by a $a->{key2} = $a->{key1}; statement that makes the value of 'key2' the same as 'key1': they're the same reference. (Update: dd works by generating source code that | source code text that, when run thru eval, will reproduce the structure of the data being dumped.)
Update: Clarified the update remark about dd per LanX's comment here. Thanks, LanX!
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
|
|
DB<61> @ra = ({a=>1, b=>2}, {a=>1, b=>2});
DB<62> print $_ for @ra
HASH(0x35a4090)HASH(0x35a3ae8) # different IDs
DB<63> @ra = ({a=>1, b=>2}) x 2;
DB<64> print $_ for @ra
HASH(0x35a3eb0)HASH(0x35a3eb0) # same IDs
DB<65>
> Update: dd works by generating source code that will reproduce the structure of the data being dumped.
... when run thru eval .
There seems to be no better generic syntax to reproduce the case of duplicated references, than stuffing a fix placeholder string into it and fixing it later.
An for completeness, here code to clone the hashes instead of copying their refs
my $value = { a=>1, b=>2 }; # curly brackets to assign hashref!
$hash{$_} = { %$value } for @keys;
### or alternatively
my %value = ( a=>1, b=>2 ); # round brackets to assign list!
$hash{$_} = { %value } for @keys;
this kind of cloning works because % returns a list in listcontext, which is packed again into a new { hash }
DB<78> x %$value
0 'a'
1 1
2 'b'
3 2
DB<79>
debugger demo
DB<72> x @keys
0 'Prefix1=A:b:1'
1 'Prefix1=A:b:2'
2 'Prefix1=A:c:1'
3 'Prefix1=A:c:2'
DB<73> x $value = {a=>1, b=>2};
0 HASH(0x35a48e8)
'a' => 1
'b' => 2
DB<74> $hash{$_} = { %$value } for @keys;
DB<75> x \%hash
0 HASH(0x3598330)
'Prefix1=A:b:1' => HASH(0x35a50b8)
'a' => 1
'b' => 2
'Prefix1=A:b:2' => HASH(0x35a4c18) # <--- differing IDs
'a' => 1
'b' => 2
'Prefix1=A:c:1' => HASH(0x35a46a8)
'a' => 1
'b' => 2
'Prefix1=A:c:2' => HASH(0x35a4a50)
'a' => 1
'b' => 2
DB<77>
| [reply] [d/l] [select] |
|
|
|
|
|
|
Thanks for that, AnomalousMonk.
"In the first, two different anonymous array references are being constructed. In the second, a single anonymous array reference is constructed and then repeated twice."
So how can we use this concise & convenient "x 2" syntax to generate the former? I've just proposed a workaround here, but maybe there's a cleaner method.
Update: It looks as if I don't actually need an alternative, because the later should work for my needs, since I'll only be reading it, according to LanX. But I'm still interested if you know of a concise efficient alternative, which would allow reading & writing.
| [reply] |
|
|
|
|
|
|
|
|
|
|
|
> What am I doing wrong, please?
The output looks right to me. You are assigning the same hashref again.
Do you need the hashes to different instances with same content?
Then you need to loop over all keys and always assign a new copy
{ %$hashref }
| [reply] [d/l] |
|
|
Thanks for that, LanX,
"Do you need the hashes to different instances with same content?"
If I understand your question correctly, then yes. See example in update #2 of my original post. It's a hash of a hash and the inner hashes have the same keys and values (for a given line of input data).
After some more experimenting, since multiplying the right hand side (e.g. with 'x2') is not going to work (the reason for which still isn't clear to me), then what would be wrong with this kind of strategy: Multiply a string first then eval it:
perl -MData::Dump -e '$val="(".("{(a,1),(b,2)},"x2).")";@hash{(key1,ke
+y2)} = eval $val;dd $val;dd \%hash'
"({(a,1),(b,2)},{(a,1),(b,2)},)"
{ key1 => { a => 1, b => 2 }, key2 => { a => 1, b => 2 } }
# Or more concisely:
perl -MData::Dump -e '@hash{(key1,key2)} = eval "(".("{(a,1),(b,2)},"x
+2).")";dd \%hash'
At least it seems to do what's required. I know there's a trailing ',' in $val which could easily be removed, but doesn't seem to be causing a problem with the resulting hash. | [reply] [d/l] |
|
|
|
|
|
|
|
|
|