Eugene Barsky
Eugene Barsky

Reputation: 5992

How to make an array of hashes in Perl 6?

How to make a hash that has been pushed into an array independent of the "source" hash?

my %country;
my Hash @array;

%country{ 'country' } = 'France';
@array.push(%country);
%country{ 'country' } = 'Germany';
@array.push(%country);

.say for @array;

The output is:

{country => Germany}
{country => Germany}

And of course it's not what I want.

Upvotes: 3

Views: 699

Answers (3)

Scimon Proctor
Scimon Proctor

Reputation: 4558

If you just want a simple key value pair (not a multi part hash) consider Pairs?

my Pair @array;
@array.push( (:country<Germany>) );
@array.push( (country => "France") );
say @array;
say .kv for @array

Upvotes: 1

piojo
piojo

Reputation: 6723

Just about every programming language has this issue. You're pushing the same hash onto the array more than once. When you change the hash, you change both references that are inside the array.

If you push different hashes onto the array, you'll see the result you expect:

my %a = ( country => 'China' );
my %b = ( country => 'USA' );
my Hash @array;
@array.push(%a);
@array.push(%b);
say @array.perl;

You can even copy the hash when you push it onto the array, instead of declaring two hashes. That will also solve this problem:

my %country;
my @array;
%country<country> = 'México';
@array.push(%country.list.hash);
%country<country> = 'Canada';
@array.push(%country.list.hash);
say @array.perl;

By the way, there are a lot of ways to copy a hash. The key is to get the key/values, then turn it back into a hash. Which hash constructor, and which flattening method you use are up to you. (.kv, .list, .pairs, .flat are all Hash methods that will get the elements sequentially, in one way or another. The way Håkon showed is more implicit, getting elements then creating another hash by syntax alone.)

Upvotes: 3

H&#229;kon H&#230;gland
H&#229;kon H&#230;gland

Reputation: 40718

When you push the hash %country on to the array you are pushing the reference to %country. In this way, each array element will reference the same original hash %country. And when you change a value of the hash all array elements will reflect this change (since they all reference the same hash). If you want to create a new hash each time you push it, you can try push an anonymous hash instead. For example:

%country{ 'country' } = 'France';
@array.push({%country});
%country{ 'country' } = 'Germany';
@array.push({%country});

In this way, a reference to a copy of %country is pushed each time (instead of a reference to %country).

Output:

{country => France}
{country => Germany}

Upvotes: 3

Related Questions