in reply to Converting python list range expressions to perl
G'day ibm1620,
I think what you're looking for is splice.
Test script:
#!/usr/bin/env perl
use v5.36;
use constant {
AREF => 0,
PYTHON => 1,
EXP => 2,
};
use Test::More;
my @test_array = 'a' .. 'g';
my @tests = (
[\@test_array, '[:3]', 'abc'],
[\@test_array, '[:-3]', 'abcd'],
[\@test_array, '[3:]', 'defg'],
[\@test_array, '[-3:]', 'efg'],
);
plan tests => 0+@tests;
for my $test (@tests) {
is get_array_slice_by_python_expr($test->@[AREF, PYTHON]),
$test->[EXP], "Testing: $test->[PYTHON]";
}
sub get_array_slice_by_python_expr ($aref, $python) {
state $re = qr{^\[(|-?\d+):(|-?\d+)\]$};
my @temp_array = $aref->@*;
my ($offset, $length) = $python =~ $re;
$offset ||= 0;
return length($length)
? join('', splice @temp_array, $offset, $length)
: join('', splice @temp_array, $offset);
}
Output:
1..4
ok 1 - Testing: [:3]
ok 2 - Testing: [:-3]
ok 3 - Testing: [3:]
ok 4 - Testing: [-3:]
Re^2: Converting python list range expressions to perl
by ibm1620 (Friar) on Dec 04, 2022 at 17:13 UTC
|
Ken, thanks for your writeup, including forcing me to learn a bit about Test -- I needed that! :-)
I'd rather stick with Perl's slice capability since it reads more cleanly (to me, anyway) and doesn't require copying and modifying the source array. Here's how I ended up implementing and testing pyrange():
#!/usr/bin/env perl
use v5.36;
use constant {
AREF => 0,
PYTHON => 1,
EXP => 2,
};
use Test::More;
my @test_array = 'a' .. 'g';
my @tests = (
[\@test_array, '[:3]', 'abc'],
[\@test_array, '[:-3]', 'abcd'],
[\@test_array, '[3:]', 'defg'],
[\@test_array, '[-3:]', 'efg'],
[\@test_array, '[-3:-1]', 'ef'], # testing double-ended ranges
[\@test_array, '[-3:-3]', ''],
[\@test_array, '[3:-1]', 'def'],
);
plan tests => 0+@tests;
for my $test (@tests) {
is get_array_slice_by_python_expr($test->@[AREF, PYTHON]),
$test->[EXP], "Testing: $test->[PYTHON]";
}
sub get_array_slice_by_python_expr ($aref, $python) {
### $re modified to return undef instead of '' when endpoint omitt
+ed
state $re = qr{^ \[ ( -? \d+ )? : ( -? \d+ )? \] $}x;
my ($start, $stop) = $python =~ $re;
my $range_aref = pyrange($aref, $start, $stop);
return join '', @$range_aref;
}
sub pyrange($aref, $start=undef, $stop=undef) {
if (!defined $start) {
$start = 0;
}
elsif ($start < 0) {
$start = @$aref + $start;
}
if (!defined $stop) {
$stop = $#$aref;
}
elsif ($stop >= 0) {
$stop = $stop - 1;
}
else {
$stop = @$aref + $stop - 1;
}
return [@$aref[$start .. $stop]];
}
Output:
$ ./test
1..7
ok 1 - Testing: [:3]
ok 2 - Testing: [:-3]
ok 3 - Testing: [3:]
ok 4 - Testing: [-3:]
ok 5 - Testing: [-3:-1]
ok 6 - Testing: [-3:-3]
ok 7 - Testing: [3:-1]
| [reply] [d/l] [select] |
|
"Ken, thanks for your writeup, including forcing me to learn a bit about Test -- I needed that! :-)"
You're welcome. It's good to be able to start a script with use v5.36;.
"I'd rather stick with Perl's slice capability since it reads more cleanly (to me, anyway) ..."
What you choose is entirely up to you.
This correlation stood out for me:
Python | Perl |
[OFFSET:LENGTH] | splice ARRAY, OFFSET, LENGTH |
[:LENGTH] | splice ARRAY, 0, LENGTH |
[OFFSET:] | splice ARRAY, OFFSET |
[:] | splice ARRAY, 0 |
"... and doesn't require copying and modifying the source array."
The source array, @test_array, is not modified at all.
The temporary copy, @temp_array,
is modified in the last statement of (my) get_array_slice_by_python_expr() function;
it's then immediately discarded as it goes out of scope.
I added your three new tests, plus a fourth ([:]), to my original code:
[\@test_array, '[-3:-1]', 'ef'],
[\@test_array, '[-3:-3]', ''],
[\@test_array, '[3:-1]', 'def'],
[\@test_array, '[:]', 'abcdefg'],
All pass:
1..8
ok 1 - Testing: [:3]
ok 2 - Testing: [:-3]
ok 3 - Testing: [3:]
ok 4 - Testing: [-3:]
ok 5 - Testing: [-3:-1]
ok 6 - Testing: [-3:-3]
ok 7 - Testing: [3:-1]
ok 8 - Testing: [:]
| [reply] [d/l] [select] |
|
| [reply] [d/l] [select] |
|
|
|
|
|
Re^2: Converting python list range expressions to perl
by Anonymous Monk on Dec 04, 2022 at 14:20 UTC
|
splice() alters the array, slice does not. I do not intend this as disagreement. I am just trying to add information to help a newbie choose between implementations.
| [reply] [d/l] |
|
"splice() alters the array, slice does not."
Which array do you believe is being altered?
"I do not intend this as disagreement."
Fair enough.
With what are you not intending to disagree?
"I am just trying to add information to help a newbie choose between implementations."
Well, I suppose we might be able to help with that.
What information are you trying to add?
Also, as it may affect the wording, is this generic information for an arbitrary newbie,
or did you have a specific newbie in mind?
| [reply] [d/l] |
|
|