Forum: Ruby Easy question

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Robert M. (Guest)
on 2006-06-08 17:21
(Received via mailing list)
I want to maintain a list of two-dimensional points and store, at list
level, the min and max values for x and y.

The minx/maxx/miny/maxy should be updated as each point is pushed onto
the list.

The following works, but it's probably not leveraging Ruby:


def add_point( p )
   @points.push(p)
    if !@minx || @minx > p.x
        @minx=p.x
    end
    if ....

Thanks in advance.
Matthew S. (Guest)
on 2006-06-08 17:52
(Received via mailing list)
On Jun 8, 2006, at 14:20, Robert M. wrote:

>    if !@minx || @minx > p.x
>        @minx=p.x
>    end
>    if ....

There's not a lot of changes you can make to something as simple as a
conditional, actually.  Even if you improve the aesthetics, there's
little practical impact in re-writing simple conditionals.

That said, you can compress each statement into a single line using
the if/unless as a modifier (like Perl).  I tend to prefer 'unless'
in this case, but that's just me.

@minx = p.x unless @minx and p.x > @minx
@minx = p.x if !@minx or @minx > p.x


matthew smillie.
Daniel S. (Guest)
on 2006-06-08 17:59
(Received via mailing list)
Robert M. wrote:
> def add_point( p )
>   @points.push(p)
>    if !@minx || @minx > p.x
>        @minx=p.x
>    end
>    if ....

@points is an array of arrays, right?

   def add_point(p)
     @points.push(p)
     @max_x = @points.inject{|max, cur| cur[0] > max[0] ? cur : max}[0]
     @min_x = @points.inject{|min, cur| cur[0] < min[0] ? cur : max}[0]
     @max_y = @points.inject{|max, cur| cur[1] > max[1] ? cur : max}[1]
     @min_y = @points.inject{|min, cur| cur[1] < min[1] ? cur : max}[1]
   end

Depending on how often you update the array, and how often you want the
min/max values, you ought to consider putting each #inject in its own
method instead:

   def max_x
     @points.inject{|max, cur| cur[0] > max[0] ? cur : max}[0]
   end


Cheers,
Daniel
Farrel L. (Guest)
on 2006-06-08 17:59
(Received via mailing list)
You could have functions that query the points in the system instead
of keeping track as you add them.

def min_x
  (@points.min{|a,b| a.x <=> b.x}).x
end

def min_y
  (@points.min{|a,b| a.y <=> b.y}).y
end

def max_x
  (@points.max{|a,b| a.x <=> b.x}.x
end

def max_y
  (@points.min{|a,b| a.y <=> b.y}).y
end
Robert M. (Guest)
on 2006-06-08 18:05
(Received via mailing list)
1)

@points is an array of point objects

class Point
  :attr_reader :x, :y
   def initialize( x, y )
      @x, @y=x,y
  end
end

2)

With inject, aren't you iterating over the entire array every time you
add a new point, such that series.add(p) becomes O n^2?
Robert M. (Guest)
on 2006-06-08 18:08
(Received via mailing list)
But doesn't that result in an iteration over the points array every time
we want to get min/max values?
Kroeger, Simon (ext) (Guest)
on 2006-06-08 18:24
(Received via mailing list)
> -----Original Message-----
> From: Robert M. [mailto:removed_email_address@domain.invalid]
> Sent: Thursday, June 08, 2006 4:06 PM
> To: ruby-talk ML
> Subject: Re: Easy question
>
> But doesn't that result in an iteration over the points array
> every time
> we want to get min/max values?
>

Yes, which is slow, but also secure. Is there a way to
remove items from your list? what happens to the minx, etc.
if you remove the smallest one?

suggestion:

def min_x
  @minx ||= (@points.min{|a,b| a.x <=> b.x}).x
end

...

def add_point( p )
   @points.push(p)
   @minx = @maxx = @miny = @maxy = nil
end

def del_point( p )
   @points.delete(p)
   @minx = @maxx = @miny = @maxy = nil
end

cheers

Simon
Farrel L. (Guest)
on 2006-06-08 18:27
(Received via mailing list)
It does and if that's a concern due to the number of points then it's
probably best to keep track of the min/max then.
Daniel S. (Guest)
on 2006-06-08 18:44
(Received via mailing list)
Robert M. wrote:
> With inject, aren't you iterating over the entire array every time you
> add a new point, such that series.add(p) becomes O n^2?

Yes, I didn't see that until after i posted :(
I actually did the #(max|min)_(x|y) thing first, and then just copied
the code after re-reading your post. My bad.

Robert M. wrote:
 > @points is an array of point objects
 >
 > class Point
 >  :attr_reader :x, :y
 >   def initialize( x, y )
 >      @x, @y=x,y
 >  end
 > end

   def max_x
     @points.inject{|max, cur| cur.x > max.x ? cur : max}.x
   end

I'd personally use that approach -- but if you're accessing the method
often, it's rather inefficient.


Daniel
This topic is locked and can not be replied to.