Range function
David Formosa (aka ? the Platypus)
dformosa at dformosa.zeta.org.au
Sun May 15 22:22:16 EDT 2005
On 15 May 2005 02:50:38 -0700, Xah Lee <xah at xahlee.org> wrote:
> Here's the Perl code.
Where did you learn to program? Its highly unlikely that a Perl
programer would ever write a range function as there is a built in
Perl function that does the same thing. If your intent is purely
accedemic then the first thing you should do is learn Perl to a much
higher grade.
> #! perl
>
> # http://xahlee.org/tree/tree.html
> # Xah Lee, 2005-05
>
> #_____ Range _____ _____ _____ _____
>
>=pod
>
> B<Range>
Its considered poor style to have function names with capital
letters. The normal convention is to use all lower case.
> Range($iMax) generates the list [1, 2, ... , $iMax].
>
> Range($iMin, $iMax) generates the list [$iMin, ... , $iMax].
>
> Range($iMin, $iMax, $iStep) uses increment $iStep, with the last
> element in the result being less or equal to $iMax. $iStep cannot be 0.
> If $iStep is negative, then the role of $iMin and $iMax are reversed.
>
> If Range fails, 0 is returned.
>
> Example:
>
> Range(5); # returns [1,2,3,4,5]
>
> Range(5,10); # returns [5,6,7,8,9,10]
>
> Range( 5, 7, 0.3); # returns [5, 5.3, 5.6, 5.9, 6.2, 6.5, 6.8]
>
> Range( 5, -4, -2); # returns [5,3,1,-1,-3]
>
>=cut
sub range {
return [1..$_[0]] if (@_==1);
return [$_[0]..$_[1]] if (@_==2);
my $lowest = shift;
my $greatest = shift;
my $increment = shift;
my $steps = ($greatest - $lowest)/$increment;
my @return = map { $_ * $increment + $lowest } (0..$steps);
return \@return;
}
This does as you wish but it far shorter and I would argue easyer for
the typical perl programer to read.
> sub Range ($;$$) {
> if (scalar @_ == 1) {return _rangeFullArgsWithErrorCheck(1,$_[0],1);};
> if (scalar @_ == 2) {return
> _rangeFullArgsWithErrorCheck($_[0],$_[1],1);};
> if (scalar @_ == 3) {return
> _rangeFullArgsWithErrorCheck($_[0],$_[1],$_[2]);};
>};
I would suggest that If you have the case where your doing a one line
if stament then you should make use of the line modifing verent of
if. Also since if produces a scalar context its not needed.
sub Range ($;$$) {
return _rangeFullArgsWithErrorCheck(1,$_[0],1) if (@_ == 1);
return _rangeFullArgsWithErrorCheck($_[0],$_[1],1) if (@_ == 2);
return _rangeFullArgsWithErrorCheck($_[0],$_[1],$_[2]) if (@_ == 3);
}
See how much neater and more readable the code is after doing that.
> sub _rangeFullArgsWithErrorCheck ($$$) {
> my ($a1, $b1, $dx) = @_;
>
> if ($dx == 0) {print "Range: increment cannot be zero."; return 0}
> elsif ($a1 == $b1) {return [$a1];}
> elsif ( ((($b1 - $a1) > 0) && ($dx < 0)) || ((($b1 - $a1) < 0) && ($dx
>> 0)) ) {print "Range: bad arguments. You have [$a1,$b1,$dx]"; return
> 0;}
> elsif ((($a1 < $b1) && ($b1 < ($a1 + $dx))) || (($a1 > $b1) && ($b1 >
> ($a1 + $dx)))) {return [$a1];}
> else { return _rangeWithGoodArgs ($a1,$b1,$dx);};
>};
This would be a great place to make use of die. Throwing an exection for an
error.
sub _rangeFullArgsWithErrorCheck ($$$) {
my ($a1, $b1, $dx) = @_;
die "Range: increment cannot be zero." unless $dx;
return [$a1] if ($a1 == $b1);
if ( ((($b1 - $a1) > 0) && ($dx < 0))
||
((($b1 - $a1) < 0) && ($dx0))) {
die "Range: bad arguments. You have [$a1,$b1,$dx]";
}
}
> sub _rangeWithGoodArgs ($$$) {
> my ($a1, $b1, $dx) = @_;
> my @result;
>
> if ($a1 < $b1) {for (my $i = $a1; $i <= $b1; $i += $dx) { push
> (@result, $i);}; }
> else {for (my $i = $a1; $i >= $b1; $i += $dx) { push (@result, $i);};
>};
> return \@result;
>};
Personally I don't like the c style while loop. I didn't like it in C
and I don't like it in perl.
--
Please excuse my spelling as I suffer from agraphia. See
http://dformosa.zeta.org.au/~dformosa/Spelling.html to find out more.
Free the Memes.
More information about the Python-list
mailing list