我试图用Ruby搞砸一下。因此,我尝试从“Programming Collective Intelligence”Ruby书中实现算法(在Python中给出)。
在第8章中,作者将方法a作为参数传递。这似乎适用于Python,但不适用于Ruby。
我这里有方法
def gaussian(dist, sigma=10.0)
foo
end
并希望使用其他方法调用此方法
def weightedknn(data, vec1, k = 5, weightf = gaussian)
foo
weight = weightf(dist)
foo
end
我得到的只是一个错误
ArgumentError: wrong number of arguments (0 for 1)
答案 0 :(得分:92)
引用块和过程的注释是正确的,因为它们在Ruby中更常见。但是如果你愿意,你可以传递一个方法。您拨打method
以获取方法,并.call
将其调用:
def weightedknn( data, vec1, k = 5, weightf = method(:gaussian) )
...
weight = weightf.call( dist )
...
end
答案 1 :(得分:88)
你想要一个proc对象:
gaussian = Proc.new do |dist, *args|
sigma = args.first || 10.0
...
end
def weightedknn(data, vec1, k = 5, weightf = gaussian)
...
weight = weightf.call(dist)
...
end
请注意,您不能在这样的块声明中设置默认参数。因此,您需要使用splat并在proc代码中设置默认值。
或者,根据您所有这些的范围,可能更容易传递方法名称。
def weightedknn(data, vec1, k = 5, weightf = :gaussian)
...
weight = self.send(weightf)
...
end
在这种情况下,您只是调用在对象上定义的方法,而不是传递完整的代码块。根据您的结构方式,您可能需要将self.send
替换为object_that_has_the_these_math_methods.send
最后但并非最不重要的是,你可以挂掉一个方法。
def weightedknn(data, vec1, k = 5)
...
weight =
if block_given?
yield(dist)
else
gaussian.call(dist)
end
end
...
end
weightedknn(foo, bar) do |dist|
# square the dist
dist * dist
end
但听起来你想要更多可重复使用的代码块。
答案 2 :(得分:37)
您可以使用method(:function)
方式将方法作为参数传递。贝娄一个非常简单的例子:
def double(a) return a * 2 end => nil def method_with_function_as_param( callback, number) callback.call(number) end => nil method_with_function_as_param( method(:double) , 10 ) => 20
答案 3 :(得分:24)
正常的Ruby方法是使用块。
所以它会是这样的:
def weightedknn( data, vec1, k = 5 )
foo
weight = yield( dist )
foo
end
并使用如下:
weightenknn( data, vec1 ) { |dist| gaussian( dist ) }
这种模式在Ruby中广泛使用。
答案 4 :(得分:12)
您可以使用方法的&
实例上的Method
运算符将方法转换为块。
示例:
def foo(arg)
p arg
end
def bar(&block)
p 'bar'
block.call('foo')
end
bar(&method(:foo))
http://weblog.raganwald.com/2008/06/what-does-do-when-used-as-unary.html
的更多详情答案 5 :(得分:0)
你必须调用函数对象的方法“call”:
weight = weightf.call( dist )
编辑:正如评论中所解释的那样,这种做法是错误的。如果您使用Procs而不是普通函数,它将起作用。
答案 6 :(得分:0)
我建议使用&符号来访问函数中的命名块。按照this article中给出的建议,您可以写出类似这样的内容(这是我工作程序的真正废料):
# Returns a valid hash for html form select element, combined of all entities
# for the given +model+, where only id and name attributes are taken as
# values and keys correspondingly. Provide block returning boolean if you
# need to select only specific entities.
#
# * *Args* :
# - +model+ -> ORM interface for specific entities'
# - +&cond+ -> block {|x| boolean}, filtering entities upon iterations
# * *Returns* :
# - hash of {entity.id => entity.name}
#
def make_select_list( model, &cond )
cond ||= proc { true } # cond defaults to proc { true }
# Entities filtered by cond, followed by filtration by (id, name)
model.all.map do |x|
cond.( x ) ? { x.id => x.name } : {}
end.reduce Hash.new do |memo, e| memo.merge( e ) end
end
Afterwerds,你可以这样调用这个函数:
@contests = make_select_list Contest do |contest|
logged_admin? or contest.organizer == @current_user
end
如果您不需要过滤选择,只需省略该块:
@categories = make_select_list( Category ) # selects all categories
Ruby块的强大功能。
答案 7 :(得分:0)
与 Proc 或 method call 类似,您也可以将 lambda 作为 weightf
参数传递:
def main
gaussian = -> (params) {
...
}
weightedknn(data, vec1, k = 5, gaussian, params)
# Use symbol :gaussian if method exists instead
end
def weightedknn(data, vec1, k = 5, weightf, params)
...
weight = weightf.call(params)
...
end
答案 8 :(得分:-5)
你也可以使用“eval”,并将该方法作为字符串参数传递,然后只需在另一种方法中对其进行评估。