Anybody wanted to have an array slice which can *modify* the original ? (Something not happening with the @array{..} slice notation). Here is a solution with just a minor cosmetic annoyance: WHATSIT: Create an array of lvalue anon's stored in an array, which then return the value (as an lvalue, which means it modifies the original).
use Data::Dump qw(dump); my @dna = qw(A T T G C); print dump \@dna; my @view = ( sub : lvalue { $dna[1] }, sub : lvalue { $dna[2] }, ); #mutate $view[0]->() = 'x'; $view[1]->() = 'x'; print dump \@dna; $view[0] = sub : lvalue { $dna[4] }; print dump \@dna; # print ["A", "T", "x", "G", "x"]
Imperfect: If you want to use the view in exchange to the original array, it does not work for this reason: the
$view[0]->()
notation (which calls the lvalue anon). One would have to find a way how this notation shall work
$view[0]
instead.

Replies are listed 'Best First'.
Re: a referencable array slice (so assigning to it modifes the original)
by kyle (Abbot) on Jun 12, 2008 at 20:08 UTC

    I think it would be just as easy to use references to the original items instead. Creating the "view" is easy (put a backslash before the slice), and it doesn't rely on lvalue subs, which are still marked as experimental in perlsub.

    use Data::Dumper; use Test::More 'no_plan'; my @dna = qw( A T T G C ); my @view = \@dna[1,2]; is( ${$view[0]}, $dna[1], '${$view[0]} is $dna[1]' ); ${$view[0]} = 'x'; is( ${$view[0]}, $dna[1], 'changing ${$view[0]} changes $dna[1]' ); print Dumper \@view; __END__ ok 1 - ${$view[0]} is $dna[1] ok 2 - changing ${$view[0]} changes $dna[1] $VAR1 = [ \'x', \'T' ]; 1..2

    The syntax for accessing the view vs. the original array is clumsy, but that's the same as if you were using lvalue subs. If you change the original array to use references also (making them equally clumsy), the views become transparent.

    my @dna = \qw( A T T G C ); my @view = @dna[1,2]; is( ${$view[0]}, ${$dna[1]}, '${$view[0]} is ${$dna[1]}' ); ${$view[0]} = 'x'; is( ${$view[0]}, ${$dna[1]}, 'changing ${$view[0]} changes ${$dna[1]}' );

    I can't say I recommend that in general, but it might work well for you, if that's your goal.

Re: a referencable array slice (so assigning to it modifes the original)
by dragonchild (Archbishop) on Jun 12, 2008 at 19:58 UTC
    Always better to wrap in a subroutine.
    use Data::Dump qw(dump); my @dna = qw(A T T G C); print +(dump \@dna),$/; my @view; make_view( \@dna, 1, \@view, 0 ); make_view( \@dna, 2, \@view, 1 ); #mutate $view[0] = 'x'; $view[1] = 'x'; print +(dump \@dna), $/; make_view( \@dna, 4, \@view, 0 ); print +(dump \@dna), $/; # print ["A", "T", "x", "G", "x"] sub make_view { my ($arr, $idx1, $view, $idx2) = @_; tie $view[$idx2], 'Overridden', sub : lvalue { $arr->[$idx1] }; return; } { package Overridden; sub TIESCALAR { my ($class, $item) = @_; return bless \$item, $class; } sub FETCH { my $self = shift; ${$self}->(); } sub STORE { my $self = shift; my ($val) = @_; ${$self}->() = $val; } }

    But, that's what I would do.


    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
      If you're going to use tie, you might as well make the following work
      my @a = qw( a b c d e ); make_view( \my @v, \@a, 2, 2 ); # @v -> splice( @a, 2, 2 ); @v = qw( x y z ); print( "@a\n" ); # a b x y z e

      similar to

      my $a = 'abcde'; substr( $a, 2, 2 ) = 'xyz'; print( "$a\n" ); # abxyze

      By the way, tie $view[$idx2], ... should be tie $view->[$idx2], ... in your code.

Re: a referencable array slice (so assigning to it modifes the original)
by TGI (Parson) on Jun 13, 2008 at 00:18 UTC

    You should be able to achieve this with Data::Alias. I can't test it, due to my need to stick with perl 5.8.8 on win32--sigh.

    use Data::Alias; use Data::Dumper; my @foo = qw( A T T G C ); alias my @view = @foo[1,2]; $view[0] = 'x'; print Dumper \@foo;


    TGI says moo

      NEARLY PERFECT: This is really superior to my lvalue idea. It even allows to use the @view as a syntactic @foo substitute. BUT: You cannot modify the @view after creation, while the lvalue solution allows to do so.
      use strict; use warnings; use Data::Alias; use Data::Dumper; my @foo = qw( A T T G C T T G C T T C ); alias my @view = ( @foo[1,2], @foo[5,6] ); push @view, @foo[7,8]; map {$_='$'} @view; print Dumper \@foo; print "nok" if $foo[7] ne '$';

        Like I said, I can't test this, but I think I see an error in your code:

        use strict; use warnings; use Data::Alias; use Data::Dumper; my @foo = qw( A T T G C T T G C T T C ); alias my @view = ( @foo[1,2], @foo[5,6] ); alias push @view, @foo[7,8]; # Added alias here. map {$_='$'} @view; print Dumper \@foo; print "nok" if $foo[7] ne '$';

        You added copies of $foo[7] and $foo[8] to @view. So you wound up with something like:

        @view |- 0: alias $foo[1] |- 1: alias $foo[2] |- 2: alias $foo[5] |- 3: alias $foo[6] |- 4: 'G' \- 5: 'C'
        When you wanted:
        @view |- 0: alias $foo[1] |- 1: alias $foo[2] |- 2: alias $foo[5] |- 3: alias $foo[6] |- 4: alias $foo[7] \- 5: alias $foo[8]

        I haven't been able to play with this, but it feels like you need to think about each scalar as either a normal value or an alias--unless you are working with whole aggregate aliases, in which case the aggregate is aliased. If my understanding is correct, in the example above we are not using whole aggregate aliases (just a slice), so individual aliases are assigned to @view.


        TGI says moo

Re: a referencable array slice (so assigning to it modifes the original)
by ysth (Canon) on Jun 18, 2008 at 16:15 UTC
    Perl has an easy way to create an array with elements aliased to arbitrary other things: subroutine parameters.
    use Data::Dumper; my @dna = qw(A T T G C); print Dumper \@dna; my $view = sub { \@_ }->(@dna[1,2]); $view->[0] = 'x'; $view->[1] = 'x'; print Dumper \@dna; $view = sub { \@_ }->( $dna[4], @$view[1..$#$view] ); $view->[0] = 'y'; $view->[1] = 'y'; print Dumper \@dna;
Re: a referencable array slice (so assigning to it modifes the original)
by jdporter (Paladin) on Jun 13, 2008 at 16:34 UTC

    Where's the "slices"? I see no slices anywhere in your "solution", and it looks like it wouldn't support slices anyway.