copy "sub" hash?

C

catebekensail

how can you extract "mary" into another hash?

%a = ('mary'=>
{'address'=>11, 'zip'=>12},
'john'=>
{'address'=>21, 'zip'=>22},
);

%b = $a{'mary'}; ???
 
S

Steve May

how can you extract "mary" into another hash?

%a = ('mary'=>
{'address'=>11, 'zip'=>12},
'john'=>
{'address'=>21, 'zip'=>22},
);

%b = $a{'mary'}; ???

You are copying a reference above.

If you were to (attempt) to print out $b{'address'} you should see
something like:

my %a = ('mary'=>
{'address'=>11, 'zip'=>12},
'john'=>
{'address'=>21, 'zip'=>22},
);

my %b = $a{'mary'};

print qq~$b{'address'}\n~;

Output ->
Reference found where even-sized list expected
Use of uninitialized value $b{"address"} in concatenation (.) or string


Copying the dereferenced value of 'mary' instead:

my %a = ('mary'=>
{'address'=>11, 'zip'=>12},
'john'=>
{'address'=>21, 'zip'=>22},
);

my %b = %{$a{'mary'}};

print qq~$b{'address'}\n~;

Output -> 11

The outer brackets are not mandatory, but I tend to use them in
dereferencing as they are an immediate visual clue as to what the code
is doing.

You could also (simpler in my book) simply take a reference rather than
copy into another hash if that works for your process....


my %a = ('mary'=>
{'address'=>11, 'zip'=>12},
'john'=>
{'address'=>21, 'zip'=>22},
);

my $mary = $a{'mary'};

print $mary->{'address'};

Output -> 11


It might be worth your time to get a handle on references... You WILL
need them sooner or later regardless and OOP is pretty much a mystery
unless you understand them.

hth,

Steve
 
R

Rainer Weikusat

Steve May said:
how can you extract "mary" into another hash?

%a = ('mary'=>
{'address'=>11, 'zip'=>12},
'john'=>
{'address'=>21, 'zip'=>22},
);

%b = $a{'mary'}; ???

You are copying a reference above.
[...]

Reference found where even-sized list expected

Not really. Assigning a list to a hash causes the contents of the list
to be turned into key/value pairs as they're encountered, eg this code

[rw@sable]~#perl -e '%h = qw(a 1 b 2); print($h{a}, ", ", $h{b}, "\n")'
1, 2

causes %h to contain a key 'a' which is mapped to 1 and a key 'b' mapped
to 2. $a{mary} returns the value associated with the key 'mary' in the
hash %a. This is a reference to a hash. Since there's no other value,
this is effectively a list of size 1. An attempt to use a reference as
hash key will end up using the stringification of the reference instead,
consequently, what

%b = $a{mary}

does is create a key a la 'HASH(0x8195c70)' in %b whose corresponding
value is undef.

[...]
Copying the dereferenced value of 'mary' instead:

my %a = ('mary'=>
{'address'=>11, 'zip'=>12},
'john'=>
{'address'=>21, 'zip'=>22},
);

my %b = %{$a{'mary'}};
[...]

The outer brackets are not mandatory, but I tend to use them in
dereferencing as they are an immediate visual clue as to what the code
is doing.

They are mandatory in this case:

[rw@sable]~#perl -e '$h{a} = {h => a}; print %$h{a};'
syntax error at -e line 1, near "$h{a"
Execution of -e aborted due to compilation errors.

The exact rules are (quoted from memory) that a simple, scalar variable
holding a reference of the appropriate type can be used anywhere an
identifier could appear as well. Further, a block returning a reference
of an appropriate type can be used instead of the 'simple, scalar
variable'. Since $h{a} is not a scalar variable, %$h{a} is a syntax
error and the second form has to be used instead which is

%{$h{a};}

when written in full. Since the semicolon can be omitted after the last
statement in a block, this can also be written as

%{$h{a}}

It is usually more convenient to use the ->-dereferencing operator
instead of the 'block returning a reference' construct where possible,
eg (showing all three ways to get the value associated with 'a' in the
hash $h refers to):

[rw@sable]~#perl -e '$h = { a => 3 }; print(join(", ", $$h{a}, ${$h}{a}, $h->{a}), "\n")'
3, 3, 3
 
P

Peter J. Holzer

how can you extract "mary" into another hash?

%a = ('mary'=>
{'address'=>11, 'zip'=>12},
'john'=>
{'address'=>21, 'zip'=>22},
);

%b = $a{'mary'}; ???

You need the key, too, not just the value:

%b = (mary => $a{'mary'});

(George's solution is equivalent if %b is empty. I leave it to you to
figure out what the difference is if %b is not empty)

hp
 
S

Steve May

Steve May said:
how can you extract "mary" into another hash?

%a = ('mary'=>
{'address'=>11, 'zip'=>12},
'john'=>
{'address'=>21, 'zip'=>22},
);

%b = $a{'mary'}; ???

You are copying a reference above.
[...]

Reference found where even-sized list expected

Not really. Assigning a list to a hash causes the contents of the list
to be turned into key/value pairs as they're encountered, eg this code

Well, that was directly copied from the error message generated when I
ran the code shown and I would expect the same message to show up for
the OP if they ran the same code. Which is why.... well you catch my drift.


[...]
The outer brackets are not mandatory, but I tend to use them in
dereferencing as they are an immediate visual clue as to what the code
is doing.

They are mandatory in this case:

Yes, I was thinking about other cases, but in this case they are. I
didn't catch that as I tend to use them all the time in dereferencing
anyway.


\s
 
R

Rainer Weikusat

Steve May said:
Steve May said:
On 05/26/2014 06:32 PM, (e-mail address removed) wrote:
how can you extract "mary" into another hash?

%a = ('mary'=>
{'address'=>11, 'zip'=>12},
'john'=>
{'address'=>21, 'zip'=>22},
);

%b = $a{'mary'}; ???


You are copying a reference above.
[...]

Reference found where even-sized list expected

Not really. Assigning a list to a hash causes the contents of the list
to be turned into key/value pairs as they're encountered, eg this code

Well, that was directly copied from the error message generated when I
ran the code shown and I would expect the same message to show up for
the OP if they ran the same code. Which is why.... well you catch my
drift.

Except that, as I already wrote, the reference isn't copied: It is
stringified and the result of that is used as a hash key (which will be
mapped to undef because nothing except the reference was provided on the
right-hand side of the assignment).

[...]
Yes, I was thinking about other cases, but in this case they are. I
didn't catch that as I tend to use them all the time in dereferencing
anyway.

As I also already wrote: There's no relation between 'brackets' and
'dereferencing': A block returning a reference of an appropriate type
can be used instead of an ordinary identifier. That's a requirement in
case such a reference isn't simply stored in a scalar variable and it
isn't possible to use the 'infix dereference operator' (->)
instead. The latter should usually be preferred, cf (other posting by me
about this topic)

https://groups.google.com/forum/#!original/comp.lang.perl.misc/sF52WmASiJ0/m8NXDrQqj5wJ
 
S

Steve May

Steve May said:
On 05/26/2014 06:32 PM, (e-mail address removed) wrote:
how can you extract "mary" into another hash?

%a = ('mary'=>
{'address'=>11, 'zip'=>12},
'john'=>
{'address'=>21, 'zip'=>22},
);

%b = $a{'mary'}; ???


You are copying a reference above.

[...]

Reference found where even-sized list expected

Not really. Assigning a list to a hash causes the contents of the list
to be turned into key/value pairs as they're encountered, eg this code

Well, that was directly copied from the error message generated when I
ran the code shown and I would expect the same message to show up for
the OP if they ran the same code. Which is why.... well you catch my
drift.

Except that, as I already wrote, the reference isn't copied: It is
stringified and the result of that is used as a hash key (which will be
mapped to undef because nothing except the reference was provided on the
right-hand side of the assignment).

Sigh.... I believe we're saying much the same thing, just with different
spins. You are probably more technically correct given that I'm just a
shade tree hacker and that's fine.

In my limited understanding the reference was not copied (correctly)
since Perl does not implicitly dereference references. Given that all
Perl arrays and hashes ONLY hold scalar values ( a string, number, or a
reference), and the OP tried to assign that single internal scalar
(reference pointer) to a hash, Perl said:

'Reference found where even-sized list expected'

Works for me.

[...]
Yes, I was thinking about other cases, but in this case they are. I
didn't catch that as I tend to use them all the time in dereferencing
anyway.

As I also already wrote: There's no relation between 'brackets' and
'dereferencing': A block returning a reference of an appropriate type
can be used instead of an ordinary identifier. That's a requirement in
case such a reference isn't simply stored in a scalar variable and it
isn't possible to use the 'infix dereference operator' (->)
instead. The latter should usually be preferred, cf (other posting by me
about this topic)

https://groups.google.com/forum/#!original/comp.lang.perl.misc/sF52WmASiJ0/m8NXDrQqj5wJ

Whatever, but I think I'll continue to go with the approach shown in
http://perldoc.perl.org/perldsc.html

"If you want to get at the thing a reference is referring to, then you
have to do this yourself using either prefix typing indicators, like
${$blah} , @{$blah} , @{$blah[$i]} , or else postfix pointer arrows,
like $a->[3] , $h->{fred} , or even $ob->method()->[3] ."

Again, works for me and I don't really care if there are technical
quibbles. Life is too short.

I DO appreciate your comments though, they make me at least think about
the box though not necessarily outside of it. :)

\s
 
R

Rainer Weikusat

Steve May said:
Steve May said:
On 05/27/2014 05:29 AM, Rainer Weikusat wrote:
On 05/26/2014 06:32 PM, (e-mail address removed) wrote:
how can you extract "mary" into another hash?

%a = ('mary'=>
{'address'=>11, 'zip'=>12},
'john'=>
{'address'=>21, 'zip'=>22},
);

%b = $a{'mary'}; ???


You are copying a reference above.

[...]

Reference found where even-sized list expected

Not really. Assigning a list to a hash causes the contents of the list
to be turned into key/value pairs as they're encountered, eg this code

Well, that was directly copied from the error message generated when I
ran the code shown and I would expect the same message to show up for
the OP if they ran the same code. Which is why.... well you catch my
drift.

Except that, as I already wrote, the reference isn't copied: It is
stringified and the result of that is used as a hash key (which will be
mapped to undef because nothing except the reference was provided on the
right-hand side of the assignment).

Sigh.... I believe we're saying much the same thing, just with
different spins. You are probably more technically correct given that
I'm just a shade tree hacker and that's fine.

In my limited understanding the reference was not copied (correctly)
since Perl does not implicitly dereference references.

The usual term for copying what some 'reference' (or pointer) refers to,
instead of copying the reference itself, would be 'deep copy' (as
opposed to 'shallow copy') but that's yet something completely
different.

-----------
my %hash_of_hopelessness = (
anger => { address => 'hell', zip => 'Ha!'},
despair => { address => 'heller', zip => 'Ha!ler'},
ragnaroek =>{ address => 'gone', zip => '?' });


my (%well_of_measles, %saubohne_des_verderbens);

# associate a copy of the reference anger refers to with fear
#
$well_of_measles{fear} = $hash_of_hopelessness{anger};
$hash_of_hopelessness{anger}{address} = 'damnation';

print($well_of_measles{fear}{address}, "\n");

# make a deep copy of the hash despair points to
#
$well_of_measles{trostlosigkeit} = {%{$hash_of_hopelessness{despair}}};
$well_of_measles{trostlosigkeit}{address} = 'Asterdam';

print($hash_of_hopelessness{despair}{address}, "\n");

# copy the keys and values of the ragnaroek hash
#
%saubohne_des_verderbens = %{$hash_of_hopelessness{ragnaroek}};

print("$_ -> $saubohne_des_verderbens{$_}\n") for keys(%saubohne_des_verderbens);

# try to use a reference as hashkey
#
my %turn_of_the_stew;
$turn_of_the_stew{{}} = {};

# key isn't a reference anymore
#
printf("%s, %s(!)\n", $_, ref($_)) for keys(%turn_of_the_stew);
--------------

[...]
As I also already wrote: There's no relation between 'brackets' and
'dereferencing': A block returning a reference of an appropriate type
can be used instead of an ordinary identifier. That's a requirement in
case such a reference isn't simply stored in a scalar variable and it
isn't possible to use the 'infix dereference operator' (->)
instead. The latter should usually be preferred, cf (other posting by me
about this topic)

https://groups.google.com/forum/#!original/comp.lang.perl.misc/sF52WmASiJ0/m8NXDrQqj5wJ

Whatever, but I think I'll continue to go with the approach shown in
http://perldoc.perl.org/perldsc.html

"If you want to get at the thing a reference is referring to, then you
have to do this yourself using either prefix typing indicators, like
${$blah} , @{$blah} , @{$blah[$i]} , or else postfix pointer arrows,
like $a->[3] , $h->{fred} , or even $ob->method()->[3] ."

I figure you believe to have found some contradiction between a text
from the 'Perl data structures intro' tutorial and the perlref exceprt
you're apparently incorrectly ascribing to me but at least insofar I'm
concerned, I have no idea what this contradiction is suppse to be ...
 
C

Charles DeRykus

how can you extract "mary" into another hash?

%a = ('mary'=>
{'address'=>11, 'zip'=>12},
'john'=>
{'address'=>21, 'zip'=>22},
);

%b = $a{'mary'}; ??

FYI, in case you missed mention of "deep copy" in this thread:

If you don't want sharing between the hashes, you'll need to clone
rather than copy. If you just "copy" the reference ("shallow copy"),
changes in one hash will be mirrored in the other.

A simple example:

%b = %a;
$b{mary}{address} = 'foo'; ## $a{mary{address} changes too;


Whereas, with a "deep copy":

use Storable qw(dclone);

my %b = %{ dclone(\%a) };
$b{mary}{address}=12; ## $a{mary}{address} stays same


See: perldoc -q recursive
 
T

Ted Zlatanov

On Mon, 26 May 2014 18:32:02 -0700 (PDT) (e-mail address removed) wrote:

c> how can you extract "mary" into another hash?
c> %a = ('mary'=>
c> {'address'=>11, 'zip'=>12},
c> 'john'=>
c> {'address'=>21, 'zip'=>22},
c> );

c> %b = $a{'mary'}; ???

Nothing to add to the great answers so far, except that the newly
released Perl 5.20.0 actually has this built-in, called a hash slice.
For a friendly summary, see
http://perltricks.com/article/92/2014/5/27/Perl-v5-20-what-you-need-to-know

Ted
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,820
Messages
2,569,721
Members
45,509
Latest member
Danish324

Latest Threads

Top