Ruby 自定义包含?对于集合
Ruby custom include? for set
我定义了一个名为 Point 的 class 如下:
class Point
def initialize (x,y)
@x, @y = x, y
end
attr_accessor :x, :y
end
在我项目的另一部分,我生成了随机点对象并将它们放入一个集合中。然而,集合中的点必须是唯一的:
(1..numObstacles).each do |n|
p = Point.new(rand(minX..maxX), rand(minY..maxY))
if !@obstacles.include?(p)
@obstacles.add(p)
end
end
我知道这不适用于唯一性约束,因为在循环的每次迭代中,p 都是不同的对象,并且 Ruby 不知道如何比较两个点对象。但是我无法想出/找到一种正确的方法来覆盖包含?方法或提供自定义比较器(如 Java)。
谢谢!
我想,您需要通过维护一个变量然后迭代该集合来使用 hack 类的东西。
(1..numObstacles).each do |n|
p, cntr = Point.new(rand(minX..maxX), rand(minY..maxY)), false
@obstacles.each { |po| cntr = true if po.x == p.x && po.y == p.y }
@obstacles.add(p) unless cntr
end
end
我们正在做的是迭代集合,然后将 cntr
设置为 true,如果我们找到重复项,然后我们将其添加到 @obstacles
Set uses Hash as storage, so you must note the following points:
- Equality of elements is determined according to Object#eql? and Object#hash.
- Set assumes that the identity of each element does not change while it is stored. Modifying an element of a set will render the set to an unreliable state.
- When a string is to be stored, a frozen copy of the string is stored instead unless the original string is already frozen.
因此您需要在 Point
class.
上覆盖并实现 eql?
和 hash
方法
这取决于您想如何实现目标。您可以在 Point
上覆盖 eql?
和 hash
(如@TomDalling 所建议),或者您可以在 @obstacles
特征类上覆盖 include?
:
class << @obstacles
def include? other
Point === other && self.any? { |p|
other.x == p.x && other.y == p.y
}
end
end
无论您只想处理 Point
,前一种方法更好。后者更具可定制性,因为您随后可以检查完全不同的对象。
请注意,无论您是否希望 Point
s 在生命周期中更改它们的值,都应使用后一种方法(根据“Set assumes that identity of each element does not change while it is stored ”)
有一个简单的解决方案:将您的 Point 设为单线:
Point = Struct.new :x, :y
然后自动定义所有必要的方法(#hash、#eql?)。
(1..numObstacles).each do |n|
p = Point.new(rand(minX..maxX), rand(minY..maxY))
@obstacles << p
@obstacles.uniq!
end
end
or if you need the number of things in the array to be a certain amount:
until @obstacles.length == numObstacles do |n|
p = Point.new(rand(minX..maxX), rand(minY..maxY))
@obstacles << p
@obstacles.uniq!
end
end
另外 numObstacles 应该是 num_obstacles。我喜欢这种方式,因为它是声明式的。 6/10 的程序员看到一个结构就去 "Awww man!!" 这不是单行,而是
我定义了一个名为 Point 的 class 如下:
class Point
def initialize (x,y)
@x, @y = x, y
end
attr_accessor :x, :y
end
在我项目的另一部分,我生成了随机点对象并将它们放入一个集合中。然而,集合中的点必须是唯一的:
(1..numObstacles).each do |n|
p = Point.new(rand(minX..maxX), rand(minY..maxY))
if !@obstacles.include?(p)
@obstacles.add(p)
end
end
我知道这不适用于唯一性约束,因为在循环的每次迭代中,p 都是不同的对象,并且 Ruby 不知道如何比较两个点对象。但是我无法想出/找到一种正确的方法来覆盖包含?方法或提供自定义比较器(如 Java)。
谢谢!
我想,您需要通过维护一个变量然后迭代该集合来使用 hack 类的东西。
(1..numObstacles).each do |n|
p, cntr = Point.new(rand(minX..maxX), rand(minY..maxY)), false
@obstacles.each { |po| cntr = true if po.x == p.x && po.y == p.y }
@obstacles.add(p) unless cntr
end
end
我们正在做的是迭代集合,然后将 cntr
设置为 true,如果我们找到重复项,然后我们将其添加到 @obstacles
Set uses Hash as storage, so you must note the following points:
- Equality of elements is determined according to Object#eql? and Object#hash.
- Set assumes that the identity of each element does not change while it is stored. Modifying an element of a set will render the set to an unreliable state.
- When a string is to be stored, a frozen copy of the string is stored instead unless the original string is already frozen.
因此您需要在 Point
class.
eql?
和 hash
方法
这取决于您想如何实现目标。您可以在 Point
上覆盖 eql?
和 hash
(如@TomDalling 所建议),或者您可以在 @obstacles
特征类上覆盖 include?
:
class << @obstacles
def include? other
Point === other && self.any? { |p|
other.x == p.x && other.y == p.y
}
end
end
无论您只想处理 Point
,前一种方法更好。后者更具可定制性,因为您随后可以检查完全不同的对象。
请注意,无论您是否希望 Point
s 在生命周期中更改它们的值,都应使用后一种方法(根据“Set assumes that identity of each element does not change while it is stored ”)
有一个简单的解决方案:将您的 Point 设为单线:
Point = Struct.new :x, :y
然后自动定义所有必要的方法(#hash、#eql?)。
(1..numObstacles).each do |n|
p = Point.new(rand(minX..maxX), rand(minY..maxY))
@obstacles << p
@obstacles.uniq!
end
end
or if you need the number of things in the array to be a certain amount:
until @obstacles.length == numObstacles do |n|
p = Point.new(rand(minX..maxX), rand(minY..maxY))
@obstacles << p
@obstacles.uniq!
end
end
另外 numObstacles 应该是 num_obstacles。我喜欢这种方式,因为它是声明式的。 6/10 的程序员看到一个结构就去 "Awww man!!" 这不是单行,而是