Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Monks; Let's say I have a two-dimensional array:
my @arr = (['a','b','c'], ['h','i','j'], ['x','y','z']);
Getting a row or part of a row is easy enough with a slice (@{$arr[1]}), but what if I want a column? Is there any way to get ('b','i','y') with a slice? Thanks.

Replies are listed 'Best First'.
Re: Slice of a multidimensional array
by broquaint (Abbot) on Mar 06, 2003 at 17:09 UTC
    my @arr = (['a','b','c'], ['h','i','j'], ['x','y','z']); print map $_->[1], @arr; __output__ biy
    See. map() for more info.
    HTH

    _________
    broquaint

Re: Slice of a multidimensional array
by BrowserUk (Patriarch) on Mar 06, 2003 at 18:04 UTC

    There are two way of looking at what constitutes a slice of a 2d array--and more for higher dimensions:)

    In the first veiw, the result is what you would get if you could notionally extend perl's @arr[n..m] syntax to a 2D array: @arr[*][n..m] which might be described as "Give me a new 2d array where each row consists of just the columns n through m of the original array". For your example array, and with n & m set to 1 & 2 respectively, this would result in

    my @vslice = (['b','c'], ['i','j'], ['y','z']);

    The second view, and the one you want, is where the resultant arrays row(s) become 1 (or more) column(s) from the original array. for the same example as above you get

    my @yxslice = ( ['b','i','y'], ['c','j','z'] );

    Two functions to produce these

    #! perl -slw use strict; use Data::Dumper; sub vslice { map{ [ @{$_}[@_] ] } @{+shift}; } sub yxslice { my $aref = shift; map{ my $i=$_; [ map{ $_->[$i] } @$aref ] } @_; } my @arr = (['a','b','c','d'], ['h','i','j','k'], ['w','x','y','z']); my @vslice = vslice \@arr, 1..2; print Dumper \@vslice; my @yxslice = yxslice \@arr, 1..2; print Dumper \@yxslice; __END__ C:\test>240941 $VAR1 = [ [ 'b', 'c' ], [ 'i', 'j' ], [ 'x', 'y' ] ]; $VAR1 = [ [ 'b', 'i', 'x' ], [ 'c', 'j', 'y' ] ];

    I would use these versions of the two functions as it simplifies the syntax of using them slightly, but prototypes are almost universally condemned.

    sub vslice (\@@) { map{ [@{$_}[@_]] } @{+shift}; } sub yxslice (\@@) { my $aref = shift; map{ my $i=$_; [ map{ $_->[$i] } @$aref ] } @_; }

    Examine what is said, not who speaks.
    1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
    2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
    3) Any sufficiently advanced technology is indistinguishable from magic.
    Arthur C. Clarke.
Re: Slice of a multidimensional array
by perlguy (Deacon) on Mar 06, 2003 at 17:41 UTC
    to expand a bit on broquaint's answer, use the following to place your vertical 'slice' into an array:
    my @arr = (['a','b','c'], ['h','i','j'], ['x','y','z']); my @first_column = map $_->[0], @arr;
    or if you'd like to simply skip that step, and go straight to iterating over them:
    my @arr = (['a','b','c'], ['h','i','j'], ['x','y','z']); for (map $_->[0], @arr) { # $_ now holds the current value of column 1 (index 0) }
    hope that helps.