Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Copying a hash to another hash problem

by Anonymous Monk
on Oct 22, 2002 at 14:15 UTC ( [id://207083]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi folks.

I have the following hash populated by the following method:
$framearray->{$frameno}{$drawerno} = $tempno;
i.e $framearray{1}{5} = 23

When I try and copy this to another hash via:
%newhash = %framearray

the newhash is empty. Any ideas why this is not working?

P.S. If I should be using a better method to populate my array then any advice greatly appreciated.

Cheers.

Sean.

Replies are listed 'Best First'.
Re: Copying a hash to another hash problem
by demerphq (Chancellor) on Oct 22, 2002 at 14:24 UTC
    It looks to me like your problem is that you arent using strict.

    The reason I say this is that the hash that $framearray->{$frameno}{$drawerno} refers to isnt %framearray, but rather an anonymous hash contained referenced by $framearray

    So you have two solutions, change the offending call to $framearray{$frameno}{$drawerno}="foo"; _or_ change the %newhash=%framearray to be %newhash=%$framearray

    But as I said this type of error would be instantly indentified by turning on strict.

    my %hash; $hash{foo}{bar}="baz"; my %new=%hash; print $new{foo}{bar},"\n"; #prints baz my $hashref; $hashref->{foo}{bar}='ref'; my %new2=%$hashref; print $new2{foo}{bar},"\n"; #prints baz
    BTW, you should realize that %x=%y will only do a shallow copy on nested HOH's. In otherword the subhash in $hash{foo} and in $new{foo} will be the same. Thus
    $new{foo}{baz}='new'; print $hash{foo}{baz},"\n"; #prints new
    Taking a deep copy is more complicated, and I wont address it unless you follow up saying that you need to do so.

    HTH

    --- demerphq
    my friends call me, usually because I'm late....

Re: Copying a hash to another hash problem
by fruiture (Curate) on Oct 22, 2002 at 14:26 UTC
    $framearray->{$frameno}{$drawerno} = $tempno;

    Looks like $framearray is a hashref

    $framearray{1}{5} = 23

    Looks like %framearray is a hash

    What do $framearray and %framearray have to do with each other? Nothing.

    %newhash = %framearray

    Copying HashesofHashes is not that easy, because they work with references, so they'll point to the same values. Have a look at the Storable module and 'dclone'

    --
    http://fruiture.de
Re: Copying a hash to another hash problem
by broquaint (Abbot) on Oct 22, 2002 at 14:28 UTC
    That should work fine for a single level hash e.g
    use Data::Dumper; my %h1 = qw(foo 1 bar 1 baz 1); my %h2 = %h1; print Dumper(\%h2); __output__ $VAR1 = { 'foo' => '1', 'bar' => '1', 'baz' => '1' };
    As for deeply copying, you could use the dclone function from Storable (which is a core module) or clone from the aptly named Clone module.
    HTH

    _________
    broquaint

Re: Copying a hash to another hash problem
by Bird (Pilgrim) on Oct 22, 2002 at 14:29 UTC
    The use of the arrow operator in $framearray->{$frameno}{$drawerno} = $tempno; implies that $framearray is actually a reference to hash, and not a hash itself. You can fix this in two ways. Either dereference the $framearray ref when copying to the new hash...
    %newhash = %{$framearray};
    Or use an actual hash instead of a reference in your original assignment statements...
    my %framearray; $framearray{$frameno}{$drawerno} = $tempno; %newhash = %framearray;
    Also, you should be aware that there is another implied arrow operator between your two hash subscripts, meaning that last assignment statement could be rewritten as...
    $framearray{$frameno}->{$drawerno} = $tempno;
    This is unavoidable as multidimensional hashes are implemented as a hash of hash refs.
    Hope this helps.
    -Bird
Re: Copying a hash to another hash problem
by mfriedman (Monk) on Oct 22, 2002 at 14:29 UTC
    First a question: Your data appears to be entirely numeric. Why are you using hashes instead of arrays?

    Secondly, your %newhash should not be empty after the copy operation, but be advised that it will contain references to the ORIGINAL second level hashes from the first assignment. Example:

    use strict; use Data::Dumper; my %first; $first{'foo'}{'bar'} = 1; $first{'foo'}{'baz'} = 2; $first{'bah'}{'oof'} = 3; print "First hash:\n"; print Dumper \%first; my %second = %first; print "\nSecond hash\n"; print Dumper \%second; print "\nFirst nested hash address: $first{'foo'}\n"; print "Second nexted hash address: $second{'foo'}\n";

    output:

    First hash: $VAR1 = { 'bah' => { 'oof' => 3 }, 'foo' => { 'baz' => 2, 'bar' => 1 } }; Second hash $VAR1 = { 'bah' => { 'oof' => 3 }, 'foo' => { 'baz' => 2, 'bar' => 1 } }; First nested hash address: HASH(0x804ee40) Second nexted hash address: HASH(0x804ee40)

      Thankyou all for your constructive replies. I can see my obvious mistake that the copy of one hash to another is fundamentally flawed in my code and has been pointed out, i'm using numeric values for both keys and values, so I will rewrite the code using arrays.

      Again, thanks for the advice.

      Cheers.

      Sean.

        i'm using numeric values for both keys and values

        Well, this isnt intrinsically a bad thing. But more often than not it is.

        The reason I say this is because if your indexes are sparse, ie 1, 500,623,7439,104029 or the like, then a hash is a much more suitable container type than an array is. (A hash would store the above usin 5 slots in a hash, an array would store at minimum 104029 elements.) However if the array is dense, 1..9,11..19,21..29 etc then an array is a more suitable approach. (Each slot in a hash is bigger than in an array, so even with the 4 wasted slots in the array would still be much smaller than the 26 allocated slots in the hash.)

        Also, the difference isnt so much due to what you store in the values, but what you store in the keys.

        Good luck and dont forget strict. :-)

        --- demerphq
        my friends call me, usually because I'm late....

Re: Copying a hash to another hash problem
by Rodney_Hampton (Initiate) on Oct 22, 2002 at 16:45 UTC
    Try using the dclone method from the Storable module.It best for deeply nested structures.

    In your case:

    use Storable qw/dclone/; $newhash=dlcone($framearray);

    Hope this helps,

    Rodney A. Hampton

Re: Copying a hash to another hash problem
by l2kashe (Deacon) on Oct 22, 2002 at 17:12 UTC
    All the posts above are good, and to the point. I'll add my .02 gold as I didn't see a post which showed you how to go about doing exactly what you were doing, the way you were doing it.. (:P say that 10 times fast... No! not 'that' :) )
    $frameno = "1"; $drawerno = "12"; $tempno = "44"; # assignment $framearray->{$frameno}{$drawerno} = $tempno; # reassignment %new_hash = %{$framearray}; # or only particular hashes thereof %some_frame = %{ $framearray->{$frameno} }; # Now if we loop through %some_frame our keys are # $drawerno and our values are the values assigned above while ( ($drawer,$val) = each(%some_frame) ) { print "$drawer -> $val\n"; } # would print # 12 -> 44
    People have stated the deal with references so I'll leave that alone. I'm simply showing how to get the data the way you were trying.

    It's my personal belief that even if I'm not necessarily doing it the "right way", I always like to be able to get it done. That way I know that at the very least I grasp the concept of whats going on. Then I'll find the module that does it appropriately. This way I learn, and implement cleanly, as opposed to getting stuck at some point, and not be able to proceed due to the fact that I may not have access to CPAN right now, and I need this done ASAP.

    Cheers and happy hacking

    /* And the Creator, against his better judgement, wrote man.c */

      I probably should have given more info to what I was attempting here.
      Basically, I have 700+ disks in a NAS environment, contained in 47 drawers within 7 frames. I want to monitor the temp of the drawers, so my array would contain (1-7) for the frames and (1-8) for the no of drawers within the frames (as they don't all contain the same no. of drawers).
      Giving as an example, (1,1) would be frame 1, drawer 1 would point to the value 30, or (5,8) would be frame 5, drawer 8 giving a value of 25.

      The reason I was copying the array, was that the next time the prog queried the temp, I could compare the arrays and notify me of any changes in the temp from the last run.

      Cheers

      Sean

        I realise it is 17 years later now, but for what it is worth now in 2019, you don't have to use a copy for this, only return a new reference / object in the acquisition function that queriers the data of your hard disks. So, don't use global hashes/arrays with this function. Then, two successive calls of the acquisition function will already return two separate instances of your data and so there is no need to copy this any further.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://207083]
Approved by krisahoch
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (3)
As of 2024-04-25 09:23 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found