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.

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 Jun 8, 2006, at 14:20, Robert Mela wrote:

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

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

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

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?

Daniel Schierbeck wrote:

## ···

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

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

Farrel Lifson wrote:

## ···

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

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

## ···

-----Original Message-----

From: Robert Mela [mailto:rmela@rcn.com]

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?

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.

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