Arrays versus list referring to question

Two questions regarding the following code:

%h1 = { 'key1' => ( 1, 2, 3 ), 'key2' => ( 4, 5, 6 ) }; %h2 = { 'key1' => [ 1, 2, 3 ], 'key2' => [ 4, 5, 6 ] }; print $(@h1{'key2'})[1]; 

Q1: What is the difference between h1 and h2? Please do not say that "one is a hash of lists and another hash of arrays" ... Rather, I want to know what this means in terms of use.

Q2: Why is the link $(@h1{'key2'})[1] in the print instruction not compiled? This is my thinking: I want to access the array / list matching "key2": @h1{'key2'} . Then I want to access the scalar at index 1 in this list / array: $(@h1{'key2'})[1] . Why is this wrong? This variable referring to things gets confused.

+4
source share
4 answers

None of them work the way you think. strictly follow the rules and use warnings.

 %h1 = { 'key1' => ( 1, 2, 3 ), 'key2' => ( 4, 5, 6 ) }; 

You are trying to assign hashref ({} construct) to a hash. It binds to a scalar and is used as a key in% h1 with a value of undef. In addition, you use the list construct (()), it is smoothed, and you create a hash:

 %href = ( key1 => 1, 2 => 3, key2 => 4, 5 => 6, ); 

In the latter case, you correctly create your hash using array refs ([] construct), but you still assign href to the hash. Do you want to:

 %h1 = ( 'key1' => [ 1, 2, 3 ], 'key2' => [ 4, 5, 6 ] ); 

This creates% h1 in the list context and your values ​​in the scalar context via the link.

+14
source

The difference: they are both wrong! :)

Lists are flat structures; you cannot have lists of lists, you just get a (one-dimensional) list.

Links are scalars. Therefore, %h1 = { ... } does not make sense. What you do is simply assign a singleton list to %h1 , which will pull together and turn into a key. It is equivalent

 %h1 = ( 'HASH(0x1fb872a0)' => undef ); 

where the key is the gated version of any memory address containing this hash link.

To make a hash of arrays, do the following:

 my %h1 = ( key1 => [ 1, 2, 3 ], key2 => [ 4, 5, 6 ] ); 

If you need a reference to a hash of arrays, you can use:

 my $ref = { key1 => [ 1, 2, 3 ], key2 => [ 4, 5, 6 ] }; 

or

 my $ref = \%h1; 

Finally, to access structure elements, you can use:

 print $h1{key2}[1]; 

or

 print $ref->{key2}[1]; 

In the latter case, we use the -> operator to dereference the structure. For subsequent levels, it -> assumed -> , but you can also write

 print $ref->{key2}->[1]; 

if you get it.

To get the full structure from a link (for example, to use keys ), you need to use another form of dereferencing:

 my @keys = keys %$ref; # or more explicitly %{ $ref } 

To get the full internal structure, this is the same thing:

 my @a2 = @{ $ref->{key2} }; 

All of this is detailed in the following excellent Perl docs:

and others.

+6
source

The difference is that the assignment of %h1 completely wrong, and the assignment of %h2 almost correct.

Perl uses parentheses to create a list that can be assigned to an array or hash:

 @a = (1, 2, 3); %a = (foo => 'bar', 7 => 3); 

Perl uses parentheses to create a list link that can be assigned to a scalar.

 $a = [ 1, 2, 3 ]; 

Perl uses curly braces to create a hash link that can be assigned to a scalar.

 $a = { key1 => 1, key2 => 2 }; 

Another important point to keep in mind is that hash table values ​​are always scalars. Perl does not have “hashes of lists”, “hashes of hashes” - these are convenience conditions that really mean “hashes of list links” and “hashes of hash links”.

With this in mind, let's look at your examples:

 %h1 = { ... }; 

already mistaken. The brackets create a hash link, which is considered as a single scalar, and what you do is equivalent to this:

 $scalar = { ... }; %h1 = ( "$scalar" => undef ); 

therefore %h1 contains one key with an ugly name, like HASH(0x54321098) , and not what you mean. Say instead

 %h1 = ( ... ) 

Moving

 %h1 = ( 'key1' => ( 1, 2, 3 ), 'key2' => ( 4, 5, 6 ) ); 

also doesn't do what looks like what you want to do. This assignment has lists, not links to lists, and another thing to keep in mind is that Perl "smooths" the lists. If you think of => as a pretty synonym for a comma (which is almost true), you will see that this assignment is equivalent to either:

 %h1 = ( 'key1', 1, 2, 3, 'key2', 4, 5, 6 ); 

or

 %h1 = ( 'key1' => 1, 2 => 3, 'key2' => 4, 5 => 6 ); 

creating a hash table with four key pairs, not two expected.

If we fix the braces around the destination %h2 , then

 %h2 = ( key1 => [ 1, 2, 3 ], key2 => [ 4, 5, 6 ] ); 

will do what you expect. Remember that hash table values ​​must be scalars and that a list reference is a scalar. Then you can say something like $h2{'key1'}[1] to get individual list items (in this case 2).

+5
source

If it compiles %h1 , this is an associative array

 ( 'HASH=(...)' => undef ) 

Since you are passing it a reference to the array, not a list of key-value pairs.

If the expression for %h1 was valid, a literal hash would be:

 { key1 => 1, 2 => 3, key2 => 4, 5 => 6 } 

Just as if you created it like this:

my% h1 = (key1 => 1, 2 => 3, key2 => 4, 5 => 6);

It processes each list together, regardless of the brackets.

As a result, you will dereference "4" (or "1") as an array - of course, you are currently trying to dereference undef .

But the chances of creating it like this, when you do @h1{'key2'} , you get a list ( '4' ) , which when calculated in a scalar context becomes '1'

Even if $h1{'key2'} points to the array @h1{'key2'} , you will get ( [ 4, 5, 6 ] ) , not ( 4, 5, 6 )

+1
source

Source: https://habr.com/ru/post/1339886/


All Articles