views:

660

answers:

7

Hello,

How can I create an anonymous hash from an existing hash?

For arrays, I use:

@x = (1, 2, 3);
my $y = [@x];

but I can't find how to do the same for a hash:

my %x = ();
my $y = ???;

Thanks

A: 

Use:

$hashref = {};
Jens
+2  A: 

If you have

my %hash = ...

then you can do

my $hashref = \%hash;
Adam Pope
Nope, that gives a reference to %hash, not an anonymous hash.
Chas. Owens
Well, it's a bit of an XY problem. He's talking about a solution to problem he hasn't described, so we really don't know if and why he needs an anonymous hash.
brian d foy
In fairness, as Brian's comment on the OP suggests, the question itself wasn't 100% clear. I originally thought he just wanted an anonymous hash (which he could do in one step), but he seems to want an anonymous copy of an existing hash. Adam thought he just wanted a reference to the hash.
Telemachus
+13  A: 
my $new_hash = { %existing_hash };

Note that this solution does not make a deep copy. Read brian's answer for explanation.

Kaarel
This only works for single level data structures.
Brad Gilbert
Thanks. I've edited the answer.
Kaarel
+8  A: 

I think you need to be careful here. Consider the following hash:

my %hash = (1 => 'one',2 => 'two');

There are two ways you can get a reference from this:

my $ref = \%hash;
my $anon = {%hash};

$ref is a reference to the original hash and can be used similarly to %hash. $anon is a reference to an anonymous copy of the original hash; it will have the same data but changing it won't change the original hash and vice versa.

So, for example, to start with both of these statements will have the same output

print $ref->{1},"\n";
> one
print $anon->{1},"\n";
> one

But if I change the original hash:

$hash{1} = "i";

They two print statements would output different values:

print $ref->{1},"\n";
> i
print $anon->{1},"\n";
> one
Dave Webb
yes, yes, yes, i know, i just couldn't find the correct syntax in the documentation for {%h}
Benoît
+1  A: 

There seem to be two things going on here, and the answers are split between answering two different possible questions.

  1. You want an anonymous hash. Easy. You can do it in one step.
  2. You want an anonymous copy of an existing hash. As Dave Webb and brian suggest, this might be if you want a reference, but you don't want to tamper with the original hash. Also easy. (Well, not exactly: see brian's answer for details on deep copies.)

If you want 1, do this:

my $hash_ref = { foo => 1, bar => 2 };

If you want 2, do this:

my %hash = ( foo => 1, bar => 2 );

# Then later
my $anon_copy_hash_ref = { %hash };

(The names are not meant for prime time.) My copy isn't ready for prime time either. See brian's post for a fuller, more precise discussion.

Telemachus
You're copy isn't a copy. :)
brian d foy
Yup, I'll add a note in the post.
Telemachus
+15  A: 

Why do you need an anonymous hash? Although the answers tell you various ways you could make an anonymous hash, we have no idea if any of them are the right solution for whatever you are trying to do.

If you want a distinct copy that you can modify without disturbing the original data, use dclone from Storable, which comes with Perl. It creates a deep copy of your data structure:

use Storable qw(dclone);
my $clone = dclone \%hash;

Consider Dave Webb's answer, but with an additional layer of references. The value for the key of c is another hash reference:

use Data::Dumper;

my %original = ( a => 1, b => 2, c => { d => 1 } );
my $copy = { %original };

print 
 "Before change:\n\n",
 Data::Dumper->Dump( [ \%original], [ qw(*original) ] ),
 Data::Dumper->Dump( [ $copy ], [ qw(copy) ] ),
 ;

$copy->{c}{d} = 'foo';

print 
 "\n\nAfter change:\n\n",
 Data::Dumper->Dump( [ \%original], [ qw(*original) ] ),
 Data::Dumper->Dump( [ $copy ], [ qw(copy) ] ),
 ;

By inspecting the output, you see that even though you have an anonymous hash, it's still linked to the original:

Before change:

%original = (
     'c' => {
        'd' => 1
      },
     'a' => 1,
     'b' => 2
   );
$copy = {
    'c' => {
       'd' => 1
     },
    'a' => 1,
    'b' => 2
  };


After change:

%original = (
     'c' => {
        'd' => 'foo'
      },
     'a' => 1,
     'b' => 2
   );
$copy = {
    'c' => {
       'd' => 'foo'
     },
    'a' => 1,
    'b' => 2
  };
brian d foy
Damn. Now my attempt to clarify looks pointless *and* incomplete.
Telemachus
A: 

A quick/easy way to achieve a deep copy:

use FreezeThaw qw(freeze thaw);
$new = thaw freeze $old;
aidan