Reputation: 735
I have an array, @array
, of array references. If I use the range operator to print elements 1 through 3 of @array
, print @array[1..3]
, perl prints the array references for elements 1 through 3.
Why when I try to dereference the array references indexed between 1 and 3, @{@array[1..3]}
, perl only dereferences and prints out the last element indexed in the range operator?
Is there a way to use the range operator while dereferencing an array?
#!/bin/perl
use strict;
use warnings;
my @array = ();
foreach my $i (0..10) {
push @array, [rand(1000), int(rand(3))];
}
foreach my $i (@array) {
print "@$i\n";
}
print "\n\n================\n\n";
print @{@array[1..3]};
print "\n\n================\n\n";
Upvotes: 6
Views: 203
Reputation: 61512
From perldata
:
Slices in scalar context return the last item of the slice.
@{ ... }
dereferences a scalar value as an array, this implies that the value being dereferenced is in scalar context. From the perldata quote above we know that this will return the last element. Therefore the result is the last element.
A more reasonable approach would be to loop through your slice and print each individual array reference:
use strict;
use warnings;
use feature qw(say);
my @array_of_arrayrefs = (
[qw(1 2 3)],
[qw(4 5 6)],
[qw(7 8 9)],
[qw(a b c)],
);
foreach my $aref ( @array_of_arrayrefs[1..3] ) {
say join ',', @$aref;
}
Upvotes: 4
Reputation:
@{@array[1..3]}
is a strange-looking construct. @{ ... }
is the array dereference operator. It needs a reference, which is a type of scalar. But @array[ ... ]
produces a list.
This is one of those situations where you need to remember the rule for list evaluation in scalar context. The rule is that there is no general rule. Each list-producing operator does its own thing. In this case, apparently the array slice operator used in scalar context returns the last element of the list. @array[1..3]
in scalar context is the same as $array[3]
.
As you have noticed, this is not useful. Array slices aren't meant to be used in scalar context
If you want to flatten a 2-dimensional nested array structure into a 1-dimensional list, use map
:
print join ' ', map { @$_ } @array[1..3]
You still use the range operator for slicing. You just need some kind of looping construct (e.g. map
) to apply the array dereference operator separately to each element of the outer array.
Upvotes: 3
Reputation: 118605
@array[1..3]
is a list of 3 array references. You can't dereference them all at once, so you should iterate over this list and dereference each element separately:
print @$_ for @array[1..3];
print "@$_\n" for @array[1..3]; # for better looking output
Upvotes: 1
Reputation: 126722
The @{ ... }
construction dereferences the scalar value of the code within the braces as an array
I'm unclear what you expect from @{ @array[1..3] }
, but the list@array[1..3]
in scalar context returns just the last element of the list -- $array[3]
-- so you are asking for @{ $array[3] }
which I guess is what you got
If you explain what you want to print then I am sure we can help, but dereferencing a list makes little sense
Upvotes: 1