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.

on 2006-06-08 17:21

on 2006-06-08 17:52

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.

on 2006-06-08 17:59

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

on 2006-06-08 17:59

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

on 2006-06-08 18:05

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?

on 2006-06-08 18:08

But doesn't that result in an iteration over the points array every time we want to get min/max values?

on 2006-06-08 18:24

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

on 2006-06-08 18:27

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.

on 2006-06-08 18:44

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