Copying a hash of hashes 
Author Message
 Copying a hash of hashes

I was convinced that this had to be a FAQ but searching the FAQ, perldata,
perlref etc has come up empty. I have also looked in the Llama, the Camel and
the Cookbook and searched Dejanews...
Either I'm going blind or noone has had this problem before, which also might
mean that this is too simple and I'm just to stupid to grasp it. ;)

In short:
How do I copy all members of a hash of hashes to a new hash?

I have tested a couple of variants but none seem to do what I want:

%h1 = %h2 just copies the pointer so the two hashes is two reference to the
          same memory
%h1 = [ %h2 ] seems to do a list ref of it, destroying the hash and gives
              runtime error when I try to use the copy as a hash
%h1 = %{ %h2 } gives another runtime error when using the copy

Is the only way to iterate over the hash copying each member depending on it's
type? If so is it possible to find out what type a specific variable has?

I have attached some code that demonstrates what I'm trying to do, it is tested
with version 5.005_02 and version 5.6.0

#!/opt/perl5/bin/perl -w

use strict;
use diagnostics;

my ($hash, $hashcopy);

# Print all members of the HoH
sub printhash {

   foreach my $k1 (keys %$hash) {
      foreach my $k2 (keys %{ $$hash{$k1} }) {
         print $k1, ": ", $k2, ":: ", $$hash{$k1}{$k2}, "\n";
      }
   }

Quote:
}

# Init a HoH and return
sub inithash {
   my %HoH;

   for my $i (1 .. 3) {
      for my $j (1 .. 3) {
         $HoH{$i}{$j} = "$i+$j";
      }
   }

   return \%HoH;

Quote:
}

sub changehash {

   my %hashcopy;

   for my $i (1 .. 3) {
# Copy each hash that is indexed by $i
      $hashcopy{$i} = $$HoH{$i};
# Change the copy
      for my $j (1 .. 3) {
         $hashcopy{$i}{$j} = "$i-$j";
      }
   }

   return \%hashcopy;

Quote:
}

$hash = inithash();
# Print the hash
printhash($hash);
$hashcopy = changehash($hash);
# This should print the same as the first time, but don't
printhash($hash);

--
                        /Stefan

Life - the ultimate practical joke



Sat, 25 Jan 2003 03:00:00 GMT  
 Copying a hash of hashes

/ In short:
/ How do I copy all members of a hash of hashes to a new hash?

/ %h1 = %{ %h2 } gives another runtime error when using the copy

I believe you need a reference where h2 is ( %h1 = %{$h2ref} ).

/ Is the only way to iterate over the hash copying each member
/ depending on it's type? If so is it possible to find out what type a
/ specific variable has?

The ref() function.

I commented out one line in changehash() that was copying the
first-level reference of the first hash to the second (so that the
first level of the copy actually pointed to the data referenced by the
original.

Since hashes can only hold scalars, they just contain pointers.  If
you known the particular depth, you can do something as below.  For
arbitrary depths, deep-copy-via-recursion is probably the way to go.

Here's my small revamp, to which I've added a little diagnostic
function at the bottom.  Tell me if does what your wanted.

(Checked under "perl, version 5.004_05 built for sun4-solaris" ... the
particular machine I'm at doesn't have anything more recent).

#!/usr/local/bin/perl -w

use strict;
use diagnostics;

my ($hash, $hashcopy);

# Print all members of the HoH
sub printhash {

   foreach my $k1 (keys %$hash) {
      foreach my $k2 (keys %{ $$hash{$k1} }) {
         print $k1, ": ", $k2, ":: ", $$hash{$k1}{$k2}, "\n";
      }
   }

Quote:
}

# Init a HoH and return
sub inithash {
   my %HoH;

   for my $i (1 .. 3) {
      for my $j (1 .. 3) {
         $HoH{$i}{$j} = "$i+$j";
      }
   }

   return \%HoH;

Quote:
}

sub changehash {

   my %hashcopy;
    for my $i (1 .. 3) {
# Copy each hash that is indexed by $i
############################################### <----
# *** Copies the address of the first intermediate
#     to the second ...
#      $hashcopy{$i} = $$HoH{$i};               <----
############################################### <----
# Change the copy
      for my $j (1 .. 3) {
           $hashcopy{$i}{$j} = "$i-$j";
        }
   }
   return \%hashcopy;

Quote:
}

$hash = inithash();
# Print the hash
printhash($hash);
$hashcopy = changehash($hash);
# This should print the same as the first time, but don't
printhash($hash);

## New Stuff #########
printf("First hash: " . $hash . "\n");
check_addr($hash);
print("\n");
printf("Hash Copy : " . $hashcopy . "\n");
check_addr($hashcopy);

sub check_addr($) {
    my $h = shift;

    foreach my $l1 (keys(%$h)) {
        foreach my $l2 (keys(%{$h->{$l1}})) {
            printf($h ."->{" .$h->{$l1}. "}->{" .$l2. "} = ".
                   "$h->{$l1}->{$l2}\n");
        }
    }

Quote:
}

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Steve Revilak



Sat, 25 Jan 2003 03:00:00 GMT  
 Copying a hash of hashes

Quote:

> In short:
> How do I copy all members of a hash of hashes to a new hash?

You can either roll your own using a loop, or install Storable and use its
dcopy (deep copy) function.

--
<Matt/>

Fastnet Software Ltd. High Performance Web Specialists
Providing mod_perl, XML, Sybase and Oracle solutions
Email for training and consultancy availability.
http://sergeant.org | AxKit: http://axkit.org



Sun, 26 Jan 2003 03:00:00 GMT  
 Copying a hash of hashes

Quote:

> I was convinced that this had to be a FAQ but searching the FAQ,
> perldata, perlref etc has come up empty. I have also looked in the
> Llama, the Camel and the Cookbook and searched Dejanews... Either I'm
> going blind or noone has had this problem before, which also might mean
> that this is too simple and I'm just to stupid to grasp it. ;)

> In short: How do I copy all members of a hash of hashes to a new hash?

Here's a 'clone' function that should return a copy of almost any given scalar,
including references to hashes of hashes (or whatever you want to put in them).

sub clone
{
        my $self = shift;
        my $class = ref( $self );
        my $retval;

        if ( $class eq '' )             # simple scalar
        {
                $retval = $self;
        }
        elsif ( $class eq 'REF' )       # reference to reference
        {
                $retval = \clone( $$self );
        }
        elsif ( UNIVERSAL::isa( $self, 'HASH' ) )
        {
                $retval = {};
                bless( $retval, $class ) if $class ne 'HASH';
                map { $retval->{ $_ } = clone( $self->{ $_ } ) } keys( %$self );
        }
        elsif ( UNIVERSAL::isa( $self, 'SCALAR' ) )
        {
                my $newValue = $$self;
                $retval = \$newValue;
                bless( $retval, $class ) if $class ne 'SCALAR';
        }
        elsif ( UNIVERSAL::isa( $self, 'ARRAY' ) )
        {


                bless( $retval, $class ) if $class ne 'ARRAY';
        }
        elsif ( UNIVERSAL::isa( $self, 'GLOB' ) )
        {
                $retval = do { \local *x };
                *$retval = *$self;
        }
        else    # CODE or IO
        {
                # warn "clone: unsupported type $class\n";
                $retval = $self;
        }
        return $retval;

Quote:
}

# Here's a test program for it:

use Data::Dumper;

my $hashRef = {
        test1 => { a => 123, b => 234 },
        test2 => { c => 345, d => 456 },
        test3 => [ 'e', 'f' ],
        test4 => \123

Quote:
};

my $newHashRef = clone($hashRef);

print Dumper($hashRef);
print Dumper($newHashRef);

--
Ned Konz
currently: Stanwood, WA

homepage:  http://bike-nomad.com



Sun, 26 Jan 2003 03:00:00 GMT  
 Copying a hash of hashes

Quote:


>> In short:
>> How do I copy all members of a hash of hashes to a new hash?

>You can either roll your own using a loop, or install Storable and use its
>dcopy (deep copy) function.

Data::Dumper would probably also work. And I think it's already
in the standard perl distribution.

HTH,
Douglas Wilson



Mon, 27 Jan 2003 03:00:00 GMT  
 Copying a hash of hashes

Quote:



>> In short: How do I copy all members of a hash of hashes to a new hash?

>Here's a 'clone' function that should return a copy of almost any given scalar,
>including references to hashes of hashes (or whatever you want to put in them).

Thanks!
This one did the trick, with a use vars qw ( *x ) it compiled without
warnings as well.

Thanks also to all the rest who responded in the group and via email.
I have learnt a lot from all of you.

Randal Schwartz pointed me to his columns at
http://www.stonehenge.com/merlyn/UnixReview
check them out if you haven't!

--
                        /Stefan

Life - the ultimate practical joke



Tue, 28 Jan 2003 03:00:00 GMT  
 Copying a hash of hashes

Quote:


> >Here's a 'clone' function that should return a copy of almost any given scalar,
> >including references to hashes of hashes (or whatever you want to put in them).

> Thanks!
> This one did the trick, with a use vars qw ( *x ) it compiled without
> warnings as well.

Be aware of that "almost any" stipulation.  In particular, it breaks
qr// elements: they look like blessed scalar refs, but the actual data
is stored in magic, not in the scalar value.  I also would be wary of
feeding it tied vars (though I didn't try it).


Tue, 28 Jan 2003 03:00:00 GMT  
 Copying a hash of hashes

Quote:

> Be aware of that "almost any" stipulation.  In particular, it breaks
> qr// elements: they look like blessed scalar refs, but the actual data
> is stored in magic, not in the scalar value.  I also would be wary of
> feeding it tied vars (though I didn't try it).

I didn't think that it was perfect. When I wrote it, it worked on the
data I had. I believe that it also doesn't clone IO handles correctly,
but haven't tried (hence the warning).

I would be interested to see if one could write a clone function in
Perl that would do the right thing for ANY data structure...

--
Ned Konz
currently: Stanwood, WA

homepage:  http://bike-nomad.com



Tue, 28 Jan 2003 03:00:00 GMT  
 Copying a hash of hashes

Quote:

> I was convinced that this had to be a FAQ but searching the FAQ, perldata,
> perlref etc has come up empty. I have also looked in the Llama, the Camel and
> the Cookbook and searched Dejanews...
> Either I'm going blind or noone has had this problem before, which also might
> mean that this is too simple and I'm just to stupid to grasp it. ;)

> In short:
> How do I copy all members of a hash of hashes to a new hash?

> I have tested a couple of variants but none seem to do what I want:

> %h1 = %h2 just copies the pointer so the two hashes is two reference to the
>           same memory
> %h1 = [ %h2 ] seems to do a list ref of it, destroying the hash and gives
>          runtime error when I try to use the copy as a hash
> %h1 = %{ %h2 } gives another runtime error when using the copy

> Is the only way to iterate over the hash copying each member depending on it's
> type? If so is it possible to find out what type a specific variable has?

> I have attached some code that demonstrates what I'm trying to do, it is tested
> with version 5.005_02 and version 5.6.0

May be you want to use Storable and its dclone method to perform a
deep copy of your HoH

HTH

--



Sat, 08 Feb 2003 03:00:00 GMT  
 
 [ 11 post ] 

 Relevant Pages 

1. Copy a hash of hashes of hashes

2. Copy a hash from Hash reference

3. D2: Two DBs one app. Am I doing this right?

4. Hashes of Hashes of Hashes of Hashes....

5. URGENT: Hash in Hash, Array in Array, Array in Hash, Hash in Array

6. accessing hashes of hashes of hashes

7. Difference/intersection of hash of hashes of hashes ...

8. question regarding hash hash hash of array

9. hash of values and array of hashes of values and array of hashes

10. sorting hash of hashes of hashes

11. Hash of Hash of Hash

12. Help with perl hashes of hashes and arrays of hashes etc

 

 
Powered by phpBB® Forum Software