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§
if !@minx || @minx > p.x
@minx=p.x
end
if …
Thanks in advance.
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.
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. wrote:
def add_point( p )
@points.push§
if !@minx || @minx > p.x
@minx=p.x
end
if …
@points is an array of arrays, right?
def add_point§
@points.push§
@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
But doesn’t that result in an iteration over the points array every time
we want to get min/max values?
-
@points is an array of point objects
class Point
:attr_reader :x, :y
def initialize( x, y )
@x, @y=x,y
end
end
-
With inject, aren’t you iterating over the entire array every time you
add a new point, such that series.add§ becomes O n^2?
-----Original Message-----
From: Robert M. [mailto:[email protected]]
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
Robert M. wrote:
With inject, aren’t you iterating over the entire array every time you
add a new point, such that series.add§ 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
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.