in reply to Selecting Ranges of 2-Dimensional Data
Reinventing the wheel wasn't too terrible... I'm still interested whether it was necessary! ;-)
<update> One doesn't need Data::Alias - see the updated getsubset here! </update>
use warnings; use strict; use Carp; use Data::Alias 'alias'; sub rangeparse { local $_ = shift; my @o; # [ row1,col1, row2,col2 ] (-1 = last row/col) if (@o=/\AR([0-9]+|n)C([0-9]+|n):R([0-9]+|n)C([0-9]+|n)\z/) {} elsif (/\AR([0-9]+|n):R([0-9]+|n)\z/) { @o=($1,1,$2,-1) } elsif (/\AC([0-9]+|n):C([0-9]+|n)\z/) { @o=(1,$1,-1,$2) } elsif (/\AR([0-9]+|n)C([0-9]+|n)\z/) { @o=($1,$2,$1,$2) } elsif (/\AR([0-9]+|n)\z/) { @o=($1,1,$1,-1) } elsif (/\AC([0-9]+|n)\z/) { @o=(1,$1,-1,$1) } else { croak "failed to parse '$_'" } $_ eq 'n' and $_=-1 for @o; return \@o; } sub getsubset { my ($data,$range) = @_; my $cols = @{$$data[0]}; @$_==$cols or croak "data not rectangular" for @$data; $range = rangeparse($range) unless ref $range eq 'ARRAY'; @$range==4 or croak "bad size of range"; my @max = (0+@$data,$cols)x2; for my $i (0..3) { alias my $r = $$range[$i]; $r=$max[$i] if $r<0; croak "index $i out of range" if $r<1 || $r>$max[$i]; } croak "bad rows $$range[0]-$$range[2]" if $$range[0]>$$range[2]; croak "bad cols $$range[1]-$$range[3]" if $$range[1]>$$range[3]; my @cis = $$range[1]-1 .. $$range[3]-1; return [ map { alias my @row = @{$$data[$_]}[@cis]; \@row } $$range[0]-1 .. $$range[2]-1 ] } use Test::More tests=>24; is_deeply rangeparse("R1"), [ 1, 1, 1,-1 ]; is_deeply rangeparse("C1"), [ 1, 1, -1, 1 ]; is_deeply rangeparse("Rn"), [ -1, 1, -1,-1 ]; is_deeply rangeparse("Cn"), [ 1,-1, -1,-1 ]; is_deeply rangeparse("R4C5"), [ 4, 5, 4, 5 ]; is_deeply rangeparse("RnCn"), [ -1,-1, -1,-1 ]; is_deeply rangeparse("R2:R3"), [ 2, 1, 3,-1 ]; is_deeply rangeparse("C2:C3"), [ 1, 2, -1, 3 ]; is_deeply rangeparse("R4:Rn"), [ 4, 1, -1,-1 ]; is_deeply rangeparse("C5:Cn"), [ 1, 5, -1,-1 ]; is_deeply rangeparse("R2C3:R4C5"), [ 2, 3, 4, 5 ]; is_deeply rangeparse("R4C3:R4C3"), [ 4, 3, 4, 3 ]; is_deeply rangeparse("R5C1:R5C9"), [ 5, 1, 5, 9 ]; is_deeply rangeparse("R2C6:R11C6"), [ 2, 6, 11, 6 ]; is_deeply rangeparse("R3C1:RnC2"), [ 3, 1, -1, 2 ]; is_deeply rangeparse("R5C4:R5Cn"), [ 5, 4, 5,-1 ]; is_deeply rangeparse("RnC2:RnC5"), [ -1, 2, -1, 5 ]; is_deeply rangeparse("R3C2:RnCn"), [ 3, 2, -1,-1 ]; my $data = [[1..10],['a'..'j'],[11..20],[51..60]]; { my $subset = getsubset($data,"R3"); is_deeply $subset, [[11..20]]; $subset->[0][5] = 66; } { my $subset = getsubset($data,"C2"); is_deeply $subset, [[2],['b'],[12],[52]]; $subset->[2][0] = 21; } { my $subset = getsubset($data,"R4C2"); is_deeply $subset, [[52]]; $subset->[0][0] = 42; } { my $subset = getsubset($data,"R2C5:R4C8"); is_deeply $subset, [['e'..'h'],[15,66,17,18],[55,56,57,58]]; $subset->[1][2] += 5; } { my $subset = getsubset($data,"C8:Cn"); is_deeply $subset, [[8..10],['h'..'j'],[18..20],[58..60]]; $subset->[1][2] = 'X'; } is_deeply $data, [ [ 1, 2, 3, 4, 5, 6, 7, 8, 9,10], [qw/a b c d e f g h i X/], [11,21,13,14,15,66,22,18,19,20], [51,42,53,54,55,56,57,58,59,60] ];
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: Selecting Ranges of 2-Dimensional Data
by Aldebaran (Curate) on Oct 26, 2018 at 22:30 UTC | |
by haukex (Archbishop) on Oct 27, 2018 at 07:50 UTC |