Ruby 覆盖#每个;我可以通过#map#select等传递参数吗?
我已经编写了自己的Ruby 覆盖#每个;我可以通过#map#select等传递参数吗?,ruby,enumerable,Ruby,Enumerable,我已经编写了自己的树类,其中包括可枚举树然后提供一个#每个函数。因此,它能够自动获取所有可枚举的函数,如#map,#select,#find,等等。到目前为止,这些都在我的代码中起作用 问题出在这里。当我为我的树编写#each时,我给了#each一个参数,它是要使用的树遍历算法的名称,例如:pre_order或:width\u first。但是现在当我调用#map或#inject或#any?等时,它只能使用默认的遍历算法。是否有任何方法可以将此参数传递给其他可枚举函数?以下是我的标准 我需要能
树
类,其中包括可枚举
<代码>树然后提供一个#每个
函数。因此,它能够自动获取所有可枚举的函数,如#map
,#select
,#find
,等等。到目前为止,这些都在我的代码中起作用
问题出在这里。当我为我的树
编写#each
时,我给了#each
一个参数,它是要使用的树遍历算法的名称,例如:pre_order
或:width\u first
。但是现在当我调用#map
或#inject
或#any?
等时,它只能使用默认的遍历算法。是否有任何方法可以将此参数传递给其他可枚举
函数?以下是我的标准
- 我需要能够对任何
可枚举
函数使用任何遍历算法。这一点非常重要,因为对于不同的算法,树可能具有非常不同的性能
- 我不想重写每个
可枚举
函数来将此参数传递给#每个
;这违背了模块的目的
这里是我的代码的缩写版本
class Tree
include Enumerable
...
# Overwrite #each, and give it the algorithm argument.
def each(algorithm = :pre_order, &block)
if TRAVERSAL_ALGORITHMS.include? algorithm
self.send(algorithm, &block)
else
self.method_missing(algorithm)
end
end
def pre_order(&block)
yield self
self.branches.each do |branch|
branch.pre_order(&block)
end
end
def post_order(&block)
...
end
def breadth_first(&block)
...
end
end
我想称之为这样的事情
tree.find(13, :breadth_first)
tree.any?(:post_order) do |node|
node.root >= 10
end
class Tree
include Enumerable
attr_accessor :traversal_algorithm
def initialize(...)
@traversal_algorithm = :pre_order
...
end
...
def each(&block)
if TRAVERSAL_ALGORITHMS.include? @algorithm
self.send(@algorithm, &block)
else
self.method_missing(@algorithm)
end
end
end
tree.traversal_algorithm = :breadth_first
tree.find(13)
tree.traversal_algorithm = :post_order
tree.any? do |node|
node.root >= 10
end
可能的答案:设置要使用的算法的实例变量。然后代码将如下所示
tree.find(13, :breadth_first)
tree.any?(:post_order) do |node|
node.root >= 10
end
class Tree
include Enumerable
attr_accessor :traversal_algorithm
def initialize(...)
@traversal_algorithm = :pre_order
...
end
...
def each(&block)
if TRAVERSAL_ALGORITHMS.include? @algorithm
self.send(@algorithm, &block)
else
self.method_missing(@algorithm)
end
end
end
tree.traversal_algorithm = :breadth_first
tree.find(13)
tree.traversal_algorithm = :post_order
tree.any? do |node|
node.root >= 10
end
算法设置如下:
tree.find(13, :breadth_first)
tree.any?(:post_order) do |node|
node.root >= 10
end
class Tree
include Enumerable
attr_accessor :traversal_algorithm
def initialize(...)
@traversal_algorithm = :pre_order
...
end
...
def each(&block)
if TRAVERSAL_ALGORITHMS.include? @algorithm
self.send(@algorithm, &block)
else
self.method_missing(@algorithm)
end
end
end
tree.traversal_algorithm = :breadth_first
tree.find(13)
tree.traversal_algorithm = :post_order
tree.any? do |node|
node.root >= 10
end
这似乎是个很糟糕的主意。我会按照Charlie的建议使用代理对象:
class Tree
class PreOrderEnumerator
include Enumerable
attr_reader :tree
def initialize(tree)
@tree = tree
end
def each(&block)
yield tree
tree.branches.each do |branch|
branch.pre_order(&block)
end
end
end
def pre_order
PreOrderEnumerator.new(self)
end
end
然后您可以这样使用:
tree.pre_order.any? {|node| node.root > 10 }
我真傻
#enum_for
的方法给了我这里所有的力量。我可以实现Charlie的语法
tree.breadth_first.find(13)
通过增加常规线路
return self.enum_for(__method__) unless block_given?
在我的每个遍历方法中。树.width_first
将返回一个枚举器
,该枚举器根据广度优先算法进行枚举;任何调用的将在内部使用该枚举的Enumerable
方法。如果您没有向每个方法传递参数,而是为每个算法返回原始树的可枚举包装的算法方法会怎么样?例如,tree.width\u first.find(13)
或者目标是作为参数实现的?这是个好主意。你能把它写下来作为一个答案吗?如果你把问题的这一部分写下来,比如“我已经想到了这个问题,但它看起来很糟糕”,而不是把它作为你问题的答案贴出来,那就更有意义了。您可以编辑您的问题并删除此答案,仍然可以这样做。哈-完全忘记了enum_for。