From: Xah Lee
Subject: [perl-python] Range function
Date: 
Message-ID: <1115951576.138445.51080@z14g2000cwz.googlegroups.com>
Today we'll be writing a function called Range. The Perl documentation
is as follows.

Perl & Python & Java Solutions will be posted in 48 hours.

This is Perl-Python a-day. See
http://xahlee.org/web/perl-python/python.html

  Xah
  ···@xahlee.org
∑ http://xahlee.org/

--------------------------

Range

     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]

From: J�rgen Exner
Subject: Re: [perl-python] Range function
Date: 
Message-ID: <3HUge.14415$nX1.6455@trnddc09>
Xah Lee wrote:
> Today we'll be writing a function called Range.

I don't think so. Unless you meant to write "Today WE'll be writing ...."

> The Perl documentation is as follows.

Bullshit. The Perl documentation is part of any Perl installation but you 
didn't link to it anywhere left alone quote it.
Actually I'm glad you didn't, it's quite large after all.

jue
From: Xah Lee
Subject: Re: Range function
Date: 
Message-ID: <1116150638.868535.10690@g14g2000cwa.googlegroups.com>
Here's the Perl code.

----------

#! perl

# http://xahlee.org/tree/tree.html
# Xah Lee, 2005-05

#_____ Range _____ _____ _____ _____

=pod

B<Range>

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 ($;$$) {
if (scalar @_ == 1) {return _rangeFullArgsWithErrorCheck(1,$_[0],1);};
if (scalar @_ == 2) {return
_rangeFullArgsWithErrorCheck($_[0],$_[1],1);};
if (scalar @_ == 3) {return
_rangeFullArgsWithErrorCheck($_[0],$_[1],$_[2]);};
};

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);};
};

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;
};

#end Range

##########
# test

use Data::Dumper;
print Dumper(Range(5,7,0.3));
From: David Formosa (aka ? the Platypus)
Subject: Re: Range function
Date: 
Message-ID: <slrnd8g0a8.4ns.dformosa@dformosa.zeta.org.au>
On 15 May 2005 02:50:38 -0700, Xah Lee <···@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.
From: Xah Lee
Subject: Re: Range function
Date: 
Message-ID: <1116150732.766217.258960@g47g2000cwa.googlegroups.com>
Here's the Python solution.

----------
# -*- coding: utf-8 -*-
# Python

# http://xahlee.org/tree/tree.html
# Xah Lee, 2005-05

# implementation note: When iStep is a decimal, rounding error
# accumulates. For example, the last item returned from
# Range(0,18,0.3) is 17.7 not 18. A remedy is to turn iStep into a
# fraction and do exact arithmetics, and possibly convert the result
# back to decimal. A lesser workaround is to split the interval as to
# do multiple smaller range and join them together.

def Range(iMin, iMax=None, iStep=None):
  if (iMax==None and iStep==None):
    return Range(1,iMin)
  if iStep==None:
    return Range(iMin,iMax,1)
  if iMin <= iMax and iStep > 0:
    if (isinstance(iStep,int) or isinstance(iStep,long)):
      return range( iMix, iMax, iStep)
    else:
      result=[];temp=iStep
      while iMin <= iMax:
        result.append(iMin)
        iMin += iStep
      return result

# test
print Range(0, 18, 0.3)
From: Peter Hansen
Subject: Re: Range function
Date: 
Message-ID: <hdGdnZ2c1uWf0BrfRVn-gQ@powergate.ca>
Xah Lee wrote:
> Here's the Python solution.
> # implementation note: When iStep is a decimal, rounding error
> # accumulates. For example, the last item returned from
> # Range(0,18,0.3) is 17.7 not 18. A remedy is to turn iStep into a
> # fraction and do exact arithmetics, and possibly convert the result
> # back to decimal. A lesser workaround is to split the interval as to
> # do multiple smaller range and join them together.

Good lord no!  The correct way is to use an integer count and simply 
multiply it each time by the step, and add that to the range.  No 
accumulation of errors then.  Where did you learn to program?
(Rhetorical question of course, as you haven't, yet.)

> def Range(iMin, iMax=None, iStep=None):
>   if (iMax==None and iStep==None):
>     return Range(1,iMin)
>   if iStep==None:
>     return Range(iMin,iMax,1)
>   if iMin <= iMax and iStep > 0:
>     if (isinstance(iStep,int) or isinstance(iStep,long)):
>       return range( iMix, iMax, iStep)
>     else:
>       result=[];temp=iStep
>       while iMin <= iMax:
>         result.append(iMin)
>         iMin += iStep
>       return result

That's some of the worst Python code I've seen recently.  Please, no one 
take this as representative of how decent Python programmers write code.

-Peter
From: Xah Lee
Subject: Re: Range function
Date: 
Message-ID: <1116174619.859728.297260@g14g2000cwa.googlegroups.com>
the previous posted solutions are badly botched.

Here's a better solution. Any further correction will appear on the
website instead. (http://xahlee.org/tree/tree.html)

Similar change needs to be made for the Perl code... Java code will
come tomorror.

By the way, the code from me are not expected to be exemplary. These
are exercises for all, also as a intro to functional programing to
industry programers. Also, later on there will be non-trivial problems.

# -*- coding: utf-8 -*-
# Python

# http://xahlee.org/tree/tree.html
# Xah Lee, 2005-05

import math;

def Range(iMin, iMax=None, iStep=None):
  if (iMax==None and iStep==None):
    return Range(1,iMin)
  if iStep==None:
    return Range(iMin,iMax,1)
  if iMin <= iMax and iStep > 0:
    if (isinstance(iStep,int) or isinstance(iStep,long)):
      return range( iMin, iMax+1, iStep)
    else:
      result=[]
      for i in range(int(math.floor((iMax-iMin)/iStep))+1):
        result.append( iMin+i*iStep)
      return result
  if iMin >= iMax and iStep < 0:
    if (isinstance(iStep,int) or isinstance(iStep,long)):
      return range( iMin, iMax-1, iStep)
    else:
      result=[]
      for i in range(int(math.floor((iMin-iMax)/-iStep))+1):
        result.append( iMin+i*iStep)
      return result
  # raise error about bad argument. To be added later.

# test
print Range(5,-4,-2)

# Thanks to Peter Hansen for a correction.

 Xah
 ···@xahlee.org
∑ http://xahlee.org/
From: Peter Hansen
Subject: Re: Range function
Date: 
Message-ID: <bOqdnZH3kpfMFhrfRVn-gg@powergate.ca>
Xah Lee wrote:
> the previous posted solutions are badly botched.

> def Range(iMin, iMax=None, iStep=None):
[snip hideous code]

> # Thanks to Peter Hansen for a correction.

Ohmigod, he's only made it worse and he's blaming me for it.  Shows what 
I get for replying to a cross-posted troll message.

Xah, don't use my name in reference to anything you do, ever, even if 
it's only to try to give me credit.

-Peter