Ruby实例变量意外更改

时间:2015-03-12 11:58:03

标签: ruby

在下面的代码中,群集有很多点。

class Cluster
  attr_accessor :centroid, :points
  def initialize(centroid, *points)
    @centroid = centroid
    @points = points
  end
end

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

Cluster对象的示例(让我们称之为c):

#<Cluster:0x007ff5c123c210
 @centroid=#<Point:0x007ff5c123c288 @x=25, @y=125>,
 @points=
  [#<Point:0x007ff5c123c238 @x=25, @y=125>,
   #<Point:0x007ff5c1020120 @x=28, @y=145>]>

我正在尝试计算点的平均值,并在不更改@centroid的情况下更新@points

我们说我有:

class Point
  def +(point)
    @x = @x + point.x
    @y = @y + point.y
    self
  end
  def /(num)
    @x = @x/num
    @y = @y/num
    self
  end
end

并计算所有点的平均值,我运行:

c.centroid = c.points.reduce(&:+)/c.points.length

然后,c更改为:

#<Cluster:0x007ff5c123c210
 @centroid=#<Point:0x007ff5c1515ec8 @x=26, @y=135>,
 @points=
  [#<Point:0x007ff5c1515ec8 @x=26, @y=135>,
   #<Point:0x007ff5c1020120 @x=28, @y=145>]>

请注意@points的第一个元素已更改。有什么建议吗?

3 个答案:

答案 0 :(得分:5)

+中的Point方法修改了该点的成员@x@y。您需要使用计算值返回一个新点:

def +(point)
  Point.new(@x + point.x, @y + point.y)
end

def /(num)
  Point.new(@x/num, @y/num)
end

答案 1 :(得分:2)

由于您未将初始值传递给reduce,因此第一个点被修改。您可以将新点作为初始值传递给reduce,该点将被修改并返回。

c.centroid = c.points.reduce(Point.new, &:+)/c.points.length

答案 2 :(得分:0)

我认为问题是由+方法修改点@x和@y值引起的。

尝试将+方法更改为:

def +(point)
  x = @x + point.x
  y = @y + point.y

  self.class.new(x, y)
end