I am trying to mess around a little bit with Ruby. Therefor I try to implement the algorithms (given in Python) from the book "Programming Collective Intelligence" Ruby.
我试着用Ruby做点什么。为此,我尝试实现《编程集体智慧》(Programming Collective Intelligence)一书中的算法(在Python中给出)。
In chapter 8 the author passes a method a as parameter. This seems to work in Python but not in Ruby.
在第8章中,作者通过一个方法a作为参数。这在Python中似乎行得通,但在Ruby中行不通。
I have here the method
这里有一个方法
def gaussian(dist, sigma=10.0)
foo
end
and want to call this with another method
用另一个方法调用它
def weightedknn(data, vec1, k = 5, weightf = gaussian)
foo
weight = weightf(dist)
foo
end
All I got is an error
我得到的只是一个错误
ArgumentError: wrong number of arguments (0 for 1)
8 个解决方案
#1
78
You want a proc object:
您需要一个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
Just note that you can't set a default argument in a block declaration like that. So you need to use a splat and setup the default in the proc code itself.
请注意,您不能在这样的块声明中设置默认参数。因此,您需要使用splat并在proc代码本身中设置默认值。
Or, depending on your scope of all this, it may be easier to pass in a method name instead.
或者,根据您的范围,可能更容易传入方法名。
def weightedknn(data, vec1, k = 5, weightf = :gaussian)
...
weight = self.send(weightf)
...
end
In this case you are just calling a method that is defined on an object rather than passing in a complete chunk of code. Depending on how you structure this you may need replace self.send
with object_that_has_the_these_math_methods.send
在这种情况下,您只是调用在对象上定义的方法,而不是传递完整的代码块。根据你的结构,你可能需要替换自我。发送与object_that_has_the_these_math_methods.send
Last but not least, you can hang a block off the method.
最后但并非最不重要的是,你可以把一个区块挂掉。
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
But it sounds like you would like more reusable chunks of code here.
但听起来你会喜欢更多可重用的代码块。
#2
85
The comments referring to blocks and Procs are correct in that they are more usual in Ruby. But you can pass a method if you want. You call method
to get the method and .call
to call it:
引用block和Procs的注释是正确的,因为它们在Ruby中更常见。但是如果需要,可以传递一个方法。您调用方法来获取方法,并调用它:
def weightedknn( data, vec1, k = 5, weightf = method(:gaussian) )
...
weight = weightf.call( dist )
...
end
#3
31
You can pass a method as parameter with method(:function)
way. Bellow a very simple example:
您可以通过方法(:函数)的方式将方法作为参数传递。下面是一个非常简单的例子:
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
#4
23
The normal Ruby way to do this is to use a block.
通常的Ruby方法是使用块。
So it would be something like:
所以会是这样的:
def weightedknn( data, vec1, k = 5 )
foo
weight = yield( dist )
foo
end
And used like:
和使用:
weightenknn( data, vec1 ) { |dist| gaussian( dist ) }
This pattern is used extensively in Ruby.
这种模式在Ruby中广泛使用。
#5
10
You can use the &
operator on the Method
instance of your method to convert the method to a block.
您可以在方法实例上使用&操作符将方法转换为块。
Example:
例子:
def foo(arg)
p arg
end
def bar(&block)
p 'bar'
block.call('foo')
end
bar(&method(:foo))
More details at http://weblog.raganwald.com/2008/06/what-does-do-when-used-as-unary.html
更多细节在http://weblog.raganwald.com/2008/06/what-does-do-when-used-as-unary.html
#6
0
You have to call the method "call" of the function object:
必须调用函数对象的方法“call”:
weight = weightf.call( dist )
EDIT: as explained in the comments, this approach is wrong. It would work if you're using Procs instead of normal functions.
编辑:正如评论中解释的,这种方法是错误的。如果你用的是Procs而不是普通的函数,它就会起作用。
#7
0
I would recommend to use ampersand to have an access to named blocks within a function. Following the recommendations given in this article you can write something like this (this is a real scrap from my working program):
我建议使用&符号来访问函数中的命名块。按照本文中给出的建议,您可以这样写(这是我的工作程序中的一个真正的碎片):
# 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, you can call this function like this:
Afterwerds,你可以这样称呼这个函数:
@contests = make_select_list Contest do |contest|
logged_admin? or contest.organizer == @current_user
end
If you don't need to filter your selection, you simply omit the block:
如果你不需要过滤你的选择,你只需要省略这个区块:
@categories = make_select_list( Category ) # selects all categories
So much for the power of Ruby blocks.
Ruby代码块的强大功能。
#8
-5
you also can use "eval", and pass the method as a string argument, and then simply eval it in the other method.
您还可以使用“eval”,并将方法作为字符串参数传递,然后在另一个方法中对其求值。
#1
78
You want a proc object:
您需要一个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
Just note that you can't set a default argument in a block declaration like that. So you need to use a splat and setup the default in the proc code itself.
请注意,您不能在这样的块声明中设置默认参数。因此,您需要使用splat并在proc代码本身中设置默认值。
Or, depending on your scope of all this, it may be easier to pass in a method name instead.
或者,根据您的范围,可能更容易传入方法名。
def weightedknn(data, vec1, k = 5, weightf = :gaussian)
...
weight = self.send(weightf)
...
end
In this case you are just calling a method that is defined on an object rather than passing in a complete chunk of code. Depending on how you structure this you may need replace self.send
with object_that_has_the_these_math_methods.send
在这种情况下,您只是调用在对象上定义的方法,而不是传递完整的代码块。根据你的结构,你可能需要替换自我。发送与object_that_has_the_these_math_methods.send
Last but not least, you can hang a block off the method.
最后但并非最不重要的是,你可以把一个区块挂掉。
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
But it sounds like you would like more reusable chunks of code here.
但听起来你会喜欢更多可重用的代码块。
#2
85
The comments referring to blocks and Procs are correct in that they are more usual in Ruby. But you can pass a method if you want. You call method
to get the method and .call
to call it:
引用block和Procs的注释是正确的,因为它们在Ruby中更常见。但是如果需要,可以传递一个方法。您调用方法来获取方法,并调用它:
def weightedknn( data, vec1, k = 5, weightf = method(:gaussian) )
...
weight = weightf.call( dist )
...
end
#3
31
You can pass a method as parameter with method(:function)
way. Bellow a very simple example:
您可以通过方法(:函数)的方式将方法作为参数传递。下面是一个非常简单的例子:
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
#4
23
The normal Ruby way to do this is to use a block.
通常的Ruby方法是使用块。
So it would be something like:
所以会是这样的:
def weightedknn( data, vec1, k = 5 )
foo
weight = yield( dist )
foo
end
And used like:
和使用:
weightenknn( data, vec1 ) { |dist| gaussian( dist ) }
This pattern is used extensively in Ruby.
这种模式在Ruby中广泛使用。
#5
10
You can use the &
operator on the Method
instance of your method to convert the method to a block.
您可以在方法实例上使用&操作符将方法转换为块。
Example:
例子:
def foo(arg)
p arg
end
def bar(&block)
p 'bar'
block.call('foo')
end
bar(&method(:foo))
More details at http://weblog.raganwald.com/2008/06/what-does-do-when-used-as-unary.html
更多细节在http://weblog.raganwald.com/2008/06/what-does-do-when-used-as-unary.html
#6
0
You have to call the method "call" of the function object:
必须调用函数对象的方法“call”:
weight = weightf.call( dist )
EDIT: as explained in the comments, this approach is wrong. It would work if you're using Procs instead of normal functions.
编辑:正如评论中解释的,这种方法是错误的。如果你用的是Procs而不是普通的函数,它就会起作用。
#7
0
I would recommend to use ampersand to have an access to named blocks within a function. Following the recommendations given in this article you can write something like this (this is a real scrap from my working program):
我建议使用&符号来访问函数中的命名块。按照本文中给出的建议,您可以这样写(这是我的工作程序中的一个真正的碎片):
# 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, you can call this function like this:
Afterwerds,你可以这样称呼这个函数:
@contests = make_select_list Contest do |contest|
logged_admin? or contest.organizer == @current_user
end
If you don't need to filter your selection, you simply omit the block:
如果你不需要过滤你的选择,你只需要省略这个区块:
@categories = make_select_list( Category ) # selects all categories
So much for the power of Ruby blocks.
Ruby代码块的强大功能。
#8
-5
you also can use "eval", and pass the method as a string argument, and then simply eval it in the other method.
您还可以使用“eval”,并将方法作为字符串参数传递,然后在另一个方法中对其求值。