Passing hashes to a function

  • Thread starter Shashank Khanvilkar
  • Start date
S

Shashank Khanvilkar

Hi,

I will appreciate if someone can give me any pointers on how to do this?

What I need:
-------------
I have two hashes (%h1 and %h2) defined as below:

$h1{a}{b} = 10;
$h1{a}{c} = 1;
$h1{b}{c} = 10;

$h2{f} = 1;
$h2{g} = 2;


I want to pass these two hashes to a function only by VALUE (i.e the
function should make a copy of the hash and may change the hash values
in this copy. But when the function returns the changes should not
affect either %h1 or %h2)

What Have I tried:
------------------
First I tried passing the hash by value. But then I realized that hashes
get flattend out. Hence this was not useful.
Then I tried passing the hashes by reference as given in the below program.
However, I observe some wierd stuff. In the below program I have two
functions passHashRef_1 and passHashRef_2.
passHashRef_1 modified Hoh(copy of %h1), while passHashRef_2 modifies
copy of %h2.
The original %h2 remains unchanged. But the original %h1 changes.. Why
is that?




#!/usr/bin/perl

my %h1;

$h1{a}{b} = 10;
$h1{a}{c} = 1;
$h1{b}{c} = 10;

$h2{f} = 1;
$h2{g} = 2;
print "Before: "; print_HoH(%h1);
passHashRef_1(\%h1, \%h2);
print "After: "; print_HoH(%h1);

print "Before: "; print_hash(%h2);
passHashRef_2(\%h1, \%h2);
print "After: "; print_hash(%h2);

sub passHashRef_1 {
my ($a, $b) = @_;
my %aa = %{$a};
my %bb = %{$b};

$aa{"a"}{"b"} = 100;
print "passHashRef_1: "; print_HoH(%aa);

}

sub passHashRef_2 {
my ($a, $b) = @_;
my %aa = %{$a};
my %bb = %{$b};

$bb{"f"} = 100;
print "passHashRef_2: "; print_hash(%bb);


}

sub print_hash {
my (%Hsh) = @_;
foreach $x (keys %Hsh) {
print "$x==>$Hsh{$x}, ";
}
print "\n";
}

sub print_HoH {
my (%graph) = @_;

foreach $x (sort keys %graph) {
foreach $n2 (sort keys %{$graph{$x}}) {
print "($x, $n2) = $graph{$x}{$n2}\n";
}
}

}
 
X

xhoster

Shashank Khanvilkar said:
Hi,

I will appreciate if someone can give me any pointers on how to do this?

What I need:
-------------
I have two hashes (%h1 and %h2) defined as below:

$h1{a}{b} = 10;
$h1{a}{c} = 1;
$h1{b}{c} = 10;

This is a HOH. If you want the inner hashes to be isolated between the
original and the copy, then you will have to do a deep copy, not just a
simple copy.

Xho
 
P

Paul Lalli

Shashank Khanvilkar said:
However, I observe some wierd stuff. In the below program I have two
functions passHashRef_1 and passHashRef_2.
passHashRef_1 modified Hoh(copy of %h1), while passHashRef_2 modifies
copy of %h2.
The original %h2 remains unchanged. But the original %h1 changes.. Why
is that?

Because in the subroutines, you are only doing a shallow copy. That is,
you are only copying the overall hash. The original hash contains
references as values. When you copy the hash, you are copying the
hash's values. That is, you are copying the references. Those
references (both the original and the copies) point to the same data.
#!/usr/bin/perl

my %h1;

$h1{a}{b} = 10;
$h1{a}{c} = 1;
$h1{b}{c} = 10;

print "Before: "; print_HoH(%h1);
passHashRef_1(\%h1, \%h2);
print "After: "; print_HoH(%h1);

sub passHashRef_1 {
my ($a, $b) = @_;
my %aa = %{$a};
my %bb = %{$b};

At this point, %aa is a copy of %h1. $aa{'a'} is a copy of $h1{'a'}.
However, $aa{'a'} and $h1{'a'} are both references, and they both refer
to the same exact data.
$aa{"a"}{"b"} = 100;

You are here modifying the value that $aa{'a'} refers to. You are
therefore also modifying the value that $h1{'a'} refers to.
print "passHashRef_1: "; print_HoH(%aa);

}

For the canonical solution to this problem, check the FAQ:

perldoc -q copy
"How do I print out or copy a recursive data structure?"

Paul Lalli
 
F

foobar

when one tries to print the keys of h1 - "a" and "b" are only printed
and not "ac" and "bc". what is the purpose of having 2 dim hash?
 
S

Shashank Khanvilkar

Thanks all, my problem was solved.
I used deep copy using dclone.. I am putting the sample program with the
necessart changes for future referece..

#!/usr/bin/perl

use Storable qw(dclone);
my %h1;

$h1{a}{b} = 10;
$h1{a}{c} = 1;
$h1{b}{c} = 10;

$h2{f} = 1;
$h2{g} = 2;
print "Before: "; print_HoH(%h1);
passHashRef_1(\%h1, \%h2);
print "After: "; print_HoH(%h1);

print "Before: "; print_hash(%h2);
passHashRef_2(\%h1, \%h2);
print "After: "; print_hash(%h2);


sub passHashRef_1 {
my ($a, $b) = @_;
my %aa = %{ dclone(\%{$a}) };
my %bb = %{$b};

$aa{"a"}{"b"} = 100;
print "passHashRef_1: "; print_HoH(%aa);

}

sub passHashRef_2 {
my ($a, $b) = @_;
my %aa = %{$a};
my %bb = %{$b};

$bb{"f"} = 100;
print "passHashRef_2: "; print_hash(%bb);


}
sub print_hash {
my (%Hsh) = @_;
foreach $x (keys %Hsh) {
print "$x==>$Hsh{$x}, ";
}
print "\n";
}

sub print_HoH {
my (%graph) = @_;

foreach $x (sort keys %graph) {
foreach $n2 (sort keys %{$graph{$x}}) {
print "($x, $n2) = $graph{$x}{$n2}\n";
}
}

}
 
C

Chris Mattern

Shashank said:
Hi,

I will appreciate if someone can give me any pointers on how to do this?

What I need:
-------------
I have two hashes (%h1 and %h2) defined as below:

$h1{a}{b} = 10;
$h1{a}{c} = 1;
$h1{b}{c} = 10;

$h2{f} = 1;
$h2{g} = 2;


I want to pass these two hashes to a function only by VALUE (i.e the
function should make a copy of the hash and may change the hash values
in this copy. But when the function returns the changes should not
affect either %h1 or %h2)

You can't. Perl functions only take a list of scalars as their argument.
You'll have to make copies yourself and pass pointers to the copies.

--
Christopher Mattern

"Which one you figure tracked us?"
"The ugly one, sir."
"...Could you be more specific?"
 
C

Charlton Wilbur

f> when one tries to print the keys of h1 - "a" and "b" are only
f> printed and not "ac" and "bc".

That's because "a" and "b" *are* the keys of h1.

f> what is the purpose of having 2 dim hash?

Keeping complicated data structures sane. Here's an example:

%info = ( cwilbur => { email => '(e-mail address removed)',
name => 'Charlton Wilbur',
occupation => 'shiftless layabout',
home_state => 'Massachusetts' },
pendley => { email => '(e-mail address removed)',
name => 'Sherm Pendley',
occupation => 'perl guru' },
uri => { email => '(e-mail address removed)',
name => 'Uri Guttman',
home_state => 'Massachusetts' } );

(Apologies, Mr. Pendley and Mr. Guttman: yours were the first two
names I thought of.)

This would become much more of an annoyance if we only had one-level
hashes to deal with. In particular, note that the set of data
available for each of us differs; this is one place where hashes
really shine.

Charlton
 
U

Uri Guttman

f> when one tries to print the keys of h1 - "a" and "b" are only
f> printed and not "ac" and "bc".

CW> That's because "a" and "b" *are* the keys of h1.

f> what is the purpose of having 2 dim hash?

CW> Keeping complicated data structures sane. Here's an example:

CW> %info = ( cwilbur => { email => '(e-mail address removed)',
CW> name => 'Charlton Wilbur',
CW> occupation => 'shiftless layabout',
CW> home_state => 'Massachusetts' },
CW> pendley => { email => '(e-mail address removed)',
CW> name => 'Sherm Pendley',
CW> occupation => 'perl guru' },
CW> uri => { email => '(e-mail address removed)',
CW> name => 'Uri Guttman',
CW> home_state => 'Massachusetts' } );

CW> (Apologies, Mr. Pendley and Mr. Guttman: yours were the first two
CW> names I thought of.)

i am only upset because you gave a job to sherm and not to me. you will
be hearing from my lawyers, dewey, cheedem and howe, in the morning!

uri
 
C

Charlton Wilbur

CW> (Apologies, Mr. Pendley and Mr. Guttman: yours were the first
CW> two names I thought of.)

uri> i am only upset because you gave a job to sherm and not to
uri> me. you will be hearing from my lawyers, dewey, cheedem and
uri> howe, in the morning!

Well, the alternative was to make you another shiftless layabout....

Charlton
 
C

Charlton Wilbur

SP> Someone wants to give me a job? Cool!

Yeah, I was inspired by rentacoder.com. Here's $20 - can you port the
entirety of Cocoa to Windows, so I can just recompile and have my code
run? kthx!

Charlton
 

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

No members online now.

Forum statistics

Threads
474,164
Messages
2,570,898
Members
47,439
Latest member
shasuze

Latest Threads

Top