1

There is a twist obviously. When I do it like that it works and contains all the keys:

my $hash = {};
$$hash{1} = "asd";
$$hash{21} = "fafafa";

for my $key (keys($hash))
{
    push($arr_ref, $key);
}

print Dumper($arr_ref);

However when I try to do it the following way I only get the number of the keys:

    my $hash = {};
    $$hash{1} = "asd";
    $$hash{21} = "fafafa";
    my $arr_ref = [];
    $arr_ref = keys($hash);

In my head both things should be the same and after all if I do it like that:

my @arr = keys($hash);

@arr will contain the keys of the hash. The question is where is the difference ?

1
  • You are confused about the nature of Perl's variable typing. For example, the line my $hash = {}; has absolutely no purpose in both your examples. Remove that line and it will make no difference. A Perl variable is the type of whatever was last assigned to it. So although the line my $arr_ref = []; makes $arr_ref a reference to an array at that point, the line $arr_ref = keys($hash) provides a scalar context to keys(), resulting in the length of the array being returned. It needs to be @$arr_ref = keys($hash) to provide an array context. Commented Jun 7, 2014 at 12:27

2 Answers 2

4

You have a few things confused here. If the sigil (the sign in front of the var name) is a $, you have a scalar value.

Here is a list of things you need to remember:

  • Both $hash and $arr_ref are references, so the variable names have a $ because they only store a memory address reference to where the actual hash/array is.
  • An array has a @ sigil, and a hash has a % sigil. So @array and %hash are both not references.
  • If you want to put a data structure into another data structure in Perl, you need to reference it. This is done by putting a \ in front of the variable name like $ref = \@array.
  • An array gets a list assigned: my @colors = ( 'red', 'green' );
  • A hash gets a list (with parenthesis) assigned: %count = ( 'red' => 5, 'green' => 2 );
  • To access a hash value, use $count{'red'}. The sigil changes to $ because the value behind the whole identifier count{'red'} is now a scalar value.
  • To access an array value, use $colors[0] (which will give 'red'.
  • The keys function returns a list.
  • Forcing a list or an array into scalar context will give its number of elements.

Now with all this knowledge you will see that when you assign keys($hash) to $arr_ref, you are forcing scalar context, thus you get the count.

  • If you want an array of the keys, use my @array = keys($hash).
  • If you want an array ref, use my $arr_ref = \keys($hash) or put the list that is returned by keys into an array ref like my $arr_ref = [ keys($hash) ].

Also note that Perl's keys built-in only recently learned to handle references. You should be giving it a hash, or dereference your hash ref like keys( %{ $hash_ref } ). This can be shortened to keys %$hash_ref.

Also, always use strict and use warnings as both will help you by telling you about things you did wrong or things that you might have gotten confused.


To illustrate some more, I have rewritten your first piece of code to three different forms.

No references:

use strict; 
use warnings;
use Data::Dumper;

my %hash = (
  1  => "asd",
  21 => "fafafa"
);

my @array_of_keys = ();
for my $key ( keys %hash )
{
  push @array_of_keys, $key;
}

print Dumper( \@array_of_keys ); # reference the array because it looks nicer in Dumper

Reference for the array:

use strict; 
use warnings;
use Data::Dumper;

my %hash = (
  1  => "asd",
  21 => "fafafa"
);

my $arrayref_of_keys = [];
for my $key ( keys %hash )
{
  push @$arrayref_of_keys, $key; # or @{ $foo }
}

print Dumper( $arrayref_of_keys ); # it's already a ref, so no need for \

All references:

use strict; 
use warnings;
use Data::Dumper;

my %hashref = {    # notice the curly braces instead of round parens
  1  => "asd",
  21 => "fafafa"
};

my $arrayref_of_keys = [];
for my $key ( keys %$hashref )   # or %{ $foo }
{
  push @$arrayref_of_keys, $key; # or @{ $foo }
}

print Dumper( $arrayref_of_keys );

I suggest you read perlref and perlreftut.

Sign up to request clarification or add additional context in comments.

3 Comments

It just got more detailed ;)
As a side note, think about when you want to use references and when you do not need to.
It is a good side note, I am just experimenting with them now so I understand them better.
3

use strict; would be helpful along with use warnings;, try

@$arr_ref = keys($hash);

as $arr_ref = keys($hash); is implicit version of $arr_ref = scalar keys($hash); and ensures scalar context in both cases.

Also notice that keys $scalar is experimental, and keys %$scalar is advised.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.