Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

reference to an array slice?

by Anonymous Monk
on Sep 25, 2003 at 21:33 UTC ( #294263=perlquestion: print w/ replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I would like to create a reference to an array slice. Given the following code:
#!/usr/bin/perl my @list = (0, 1, 2, 3, 4, 5, 6, 7); print "@list\n"; my @short = @list[1..4]; print "@short\n"; my $ref = \{@list[2..4]}; print "@$ref\n";
Upon execution, I get the following result:
0 1 2 3 4 5 6 7 1 2 3 4 Not an ARRAY reference at test.pl line 7.
...which complains about the reference in the final print statement.

Of course, I can take the indirect route of copying the array slice into another array of which I can get the reference:

#!/usr/bin/perl my @list = (0, 1, 2, 3, 4, 5, 6, 7); print "@list\n"; my @short = @list[1..4]; print "@short\n"; my $ref = \@short; print "@$ref\n";
...but I would think that I could do this directly. Any illumination any of you would be appreciated. Thanks.

Comment on reference to an array slice?
Select or Download Code
Re: reference to an array slice?
by Enlil (Parson) on Sep 25, 2003 at 21:41 UTC
    Change this line:
    my $ref = \{@list[2..4]};
    to
    my $ref = [@list[2..4]]
    and you should have what you want.

    (update: well not a reference but a copy, as my fellow monks have kindly pointed out, and sauoq (among others) explains nicely below).

    What $ref is holding is a reference to a reference of an anonymous hash. (what happens with the curly braces, rather than with the square ones.) As Data::Dumper clearly shows:

    #!/usr/bin/perl use Data::Dumper; use strict; use warnings; my @list = (0, 1, 2, 3, 4, 5, 6, 7); print "@list\n"; my @short = @list[1..4]; print "@short\n"; my $ref = \{@list[2..4]}; print Dumper $ref; __DATA__ 0 1 2 3 4 5 6 7 1 2 3 4 Odd number of elements in anonymous hash at C:\test_bed\testme.pl line + 10. $VAR1 = \{ '4' => undef, '2' => 3 };

    -enlil

      As Limbic~Region points out in his reply, this isn't the same thing as a "reference to a slice". It is functionally equivalent to making a copy of the slice and using a reference to that copy.

      -sauoq
      "My two cents aren't worth a dime.";
      
Re: reference to an array slice?
by Limbic~Region (Chancellor) on Sep 25, 2003 at 21:41 UTC
    Anonymous Monk,
    You could turn the array slice into an anonymous array:
    #!/usr/bin/perl -w use strict; my @list = (0, 1, 2, 3, 4, 5, 6, 7); my $ref = [@list[2..4]]; print @$ref;

    The thing is that it will not reflect changes in the original array. If you want to do that, you need to make a ref to the original array and then use a slice when you dereference it.

    When you are not getting what you expect by de-referencing something, you can always do print ref $ref, $/;

    Cheers - L~R

Re: reference to an array slice?
by Abigail-II (Bishop) on Sep 25, 2003 at 21:42 UTC
    You can't take a reference to a slice. You have to copy. But you can do that with just a slight change of your first program. A one line change (and one char less!)
    #!/usr/bin/perl use strict; use warnings; my @list = (0, 1, 2, 3, 4, 5, 6, 7); print "@list\n"; my @short = @list[1..4]; print "@short\n"; my $ref = [@list[2..4]]; # <--- Change this line. print "@$ref\n"; __END__ 0 1 2 3 4 5 6 7 1 2 3 4 2 3 4

    Abigail

Re: reference to an array slice?
by sauoq (Abbot) on Sep 25, 2003 at 21:49 UTC
    ...but I would think that I could do this directly.

    You can't.

    You might approach it by making a class that held a reference to the array as well as the offset and length of the slice you were interested in. Or you might create a tie'd array that was based on a reference to the original, and kept information about offset and length and then work with a reference to the tie'd array. That would be very messy and probably wouldn't be worth it though. You'd have to gracefully handle things like the length of the original array changing...

    Working with a copy of the slice is probably best.

    -sauoq
    "My two cents aren't worth a dime.";
    
Re: reference to an array slice?
by BrowserUk (Pope) on Sep 25, 2003 at 22:12 UTC

    You can't take a ref to an array slice, but you can get an array of refs to a slice of an array. The difference is subtle, but it has many of the same benefits.

    my @a = (0..9); my @b = ( \( @a ) )[0..4]; ${ $b[3] } = 'It changed'; print "@a"; 0 1 2 It changed 4 5 6 7 8 9

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
    If I understand your problem, I can solve it! Of course, the same can be said for you.

Re: reference to an array slice?
by exussum0 (Vicar) on Sep 26, 2003 at 02:57 UTC
    Just to add to the meham. Mayham. mmmm.. ham.

    In c, a pointer to an array is just a pointer to a part of memory which describes how big your elements are. More importantly, it's to the beginning of the array.

    Perl's arrays are funky compared to that. Just like java. A perl array is a struture that has a lot of sugar on it, plus the internal array. What an array reference is, is a pointer to one of these sugar coated structures. You can't point to an internal of it and expect it to work.

    As people have shown, you can copy the data, and hell, copy references to the particular data (scalar refs) into a new array.. an anonymous one that is held on by reference.

    ---
    Play that funky music white boy..

Re: reference to an array slice?
by broquaint (Abbot) on Sep 26, 2003 at 10:25 UTC
    Contrary to the above nodes this can be done, but perhaps not as exactly as you had envisaged
    { package Tie::Array::Slice; use Tie::Array; @ISA = 'Tie::StdArray'; use Data::Dumper; use strict; sub FETCH { ${ $_[0]->[ $_[1] ] } } sub STORE { ref $_[2] ? $_[0]->[ $_[1] ] = $_[2] : ${ $_[0]->[ $_[1] ] } = $_[2]; } } use strict; my @a = qw/ one two three four /; tie my @b, 'Tie::Array::Slice'; @b = (\(@a))[1 .. 2]; print "\$b[1]: $b[1]\n"; print "\$a[2]: $a[2]\n"; print "before \@a: @a\n"; $b[0] = 'xxx'; print "after \@a: @a\n"; __output__ $b[1]: three $a[2]: three before @a: one two three four after @a: one xxx three four
    Or if you're in feeling devious then TheDamian illustrates how alias an array slice in this perl6-language post in perl5 :>
    HTH

    _________
    broquaint

      It's a tad more efficient to use perl's built-in aliasing mechanism instead of a tie, at the slight cost of using an array reference rather than an array direct.

      P:\test>test3 1 2 3 4 It changed 6 So did this 8 9 10 Rate tie sub tie 473/s -- -96% sub 11689/s 2370% -- 0 0 0 -15402 -15402 -15402 -15402 -15402 0 0

      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
      If I understand your problem, I can solve it! Of course, the same can be said for you.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://294263]
Approved by LazerRed
Front-paged by gmax
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (3)
As of 2014-09-15 05:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite cookbook is:










    Results (145 votes), past polls