Reputation: 40152
How do you concatenate arrays of aliases in Perl such that the resulting array also contains aliases?
The solution that I came up with is:
my ($x, $y, $z) = 1 .. 3;
my $a1 = sub {\@_}->($x);
my $a2 = sub {\@_}->($y, $z);
my $a3 = sub {\@_}->(@$a1, @$a2);
say "@$a3"; # 1 2 3
$_++ for $x, $y, $z;
say "@$a3"; # 2 3 4
What I am not crazy about is that to create $a3
I have to completely unpack $a1
and $a2
. For short arrays this isn't a problem, but as the data grows larger, it means that all array operations on aliased arrays are O(n)
, including traditionally O(1)
operations like push
or unshift
.
Data::Alias
could help, but it doesn't work with the latest versions of Perl. Array::RefElem
contains wrappers around the api primitives av_store
and av_push
which can be used to implement this functionality. So something like this could work:
sub alias_push (\@@) {
if (eval {require Array::RefElem}) {
&Array::RefElem::av_push($_[0], $_) for @_[1 .. $#_]
} else {
$_[0] = sub {\@_}->(@{$_[0]}, @_[1 .. $#_])
}
}
I am interested to know if there are any other ways. Particularly if there are any other ways using only the core modules.
Upvotes: 6
Views: 269
Reputation: 132896
Is this one of the cases where you might want a linked list in Perl? Steve Lembark has a talk about the various cases where people should reconsider rolling and unrolling arrays.
I'm curious why you have to do things this way though. Not that I suspect anything odd; I'm just curious about the problem.
Upvotes: 1