对于类NumberSet
,我必须定义[]
方法,以便它接受一个参数,它用作过滤器来选择集合的成员并返回包含这些元素的新集合
例如,我有
Filter.new { |number| number.even? }
和
SignFilter.new(:non_negative)
这是我必须构建的类。
我还必须定义&
和|
运算符,以便它们可以使用过滤器。
numbers[SignFilter.new(:non_negative) & Filter.new { |number| number.even? }]
到目前为止的课程是:
class NumberSet
include Enumerable
def initialize
@arr=[]
end
def each (&block)
@arr.each do |member|
block.call (member)
end
end
def << number
@arr<<number unless @arr.include?(number)
end
end
对于Filter
我觉得有点像:
class Filter
def initialize
yield
end
end
我最大的问题是[]
,$
和|
部分,我不知道该怎么做。
我想要完成的是:
numbers = NumberSet.new
[-3, -2, -1, 0, 1, 2, 3, 4, 5].each do |number|
numbers << number
end
numbers[SignFilter.new(:non_negative) & Filter.new { |number| number.even?}].to_a
#=>[0, 2, 4]
答案 0 :(得分:0)
由于这似乎是一个家庭作业问题,我不打算全面实施,但我会在你的路上看到你。您需要认识到的最重要的事情是,[]
和|
等方法可以定义为Ruby中的常规方法。在Ruby中,您只需将消息(例如[]
)发送到&#34;接收器&#34;。如何处理这些方法是通过类定义上的def
指令定义的。所以,例如:
class Filter
def |(other_filter)
# Do some work to build a new filter which is a union of this filter and other_filter
end
end
class SignFilter < Filter
# SignFilter inherits the & method from Filter, and you can then go on to implement SignFilter-specific functionality
# ...
end
class NumberSet
def [](filter)
# Given a filter, apply each of the numbers of this NumberSet to the filter, and return those which pass the filter
end
end
要调用这些方法,可以执行以下操作:
filter = Filter.new {|num| num.even? }
sign_filter = SignFilter.new(:non_negative)
union_filter = filter | sign_filter
这第三行相当于调用:
union_filter = filter.|(sign_filter)
或:
union_filter = filter.send("|", sign_filter)
在所有三种情况下,&#34; |&#34;消息被发送到filter
实例,其中sign_filter
作为附加参数。你也可以这样做:
numset = NumberSet.new(1,2,3,4,5)
filtered_numbers = numset[union_filter]
这第二行相当于:
numset.[](union_filter)
# or
numset.send("[]", union_filter)
原始语法只是那些方法调用的语法糖 - 它只是因为它使Ruby代码看起来更好,并帮助程序员在心理上将它映射到这些操作的常用约定。
答案 1 :(得分:0)
我认为应该这样做。
<强>代码强>
SignFilter类
class SignFilter
def initialize(sign)
@sign = sign
end
def filter
case @sign
when :negative
-> i { i < 0 }
when :positive
-> i { i > 0 }
when :non_negative
-> i { i >= 0 }
when :non_positive
-> i { i <= 0 }
when :zero
-> i { i.zero? }
end
end
end
过滤类
class Filter
attr_reader :filter
def initialize &filter
@filter = filter
end
end
NumberSet类
class NumberSet
def initialize arr
@arr = arr
end
def process(op, sf, f)
sign_filter = sf.filter
filter = f.filter
@arr.send(op).each { |e| sign_filter.call(e) }
.send(op).each { |e| filter.call(e) }
end
end
<强>实施例强>
sf = SignFilter.new :negative
f = Filter.new { |number| number.even? }
ns = NumberSet.new [-3, -2, -1, 0, 1, 2, 3, 4, 5]
ns.process(:reject, sf, f)
#=> [1, 3, 5]
sf = SignFilter.new :non_negative
f = Filter.new { |number| number % 3 == 0 }
ns = NumberSet.new [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6]
ns.process(:select, sf, f)
#=> [0, 3, 6]
<强>解释强>
块不是对象,因此您无法传递它们。但是,它们可以转换为procs,它们是对象(类Proc的实例),因此可以传递。你需要了解procs(和lambdas,它们是proc的一种类型)。 Here是一个很好的解释。 (旁白:有一点让人感到困惑的是,可以通过多种方式调用它们。例如,如果p -> i { 3*i }
,p.call(2)
,p.yield(2)
,p[2]
和{ {1}}都返回值p.(2)
。)
以下是发生的事情:
6
类的实例sf
(SignFilter
,{{1 }} 等等)。符号保存在实例变量:negative
中。:non_negative
类的方法@sign
根据SignFilter
的值返回filter
。lambda
类的实例是通过传递一个块来创建的,该块作为@sign
接收并保存到具有读取访问器的实例变量Filter
中。proc
类的实例,该数组保存在实例变量@filter
中。NumberSet
传递三个参数:可枚举方法@arr
或NumberSet#process
(保存到:reject
),:select
实例(op
)和SignFilter
实例(sf
)。Filter
内,f
已发送NumberSet#process
,这会创建一个枚举器(@arr
或op
。arr.reject
lambda。返回由arr.select)
的子集合组成的数组。SignFilter
,创建另一个@arr
或op
枚举器。reject
proc,导致返回所需的数组。考虑到select
和Filter
都不是必需的(要么会这样做),只需将reject
中的select
替换为.send(op)
就更简单了{ {1}},但我选择这样做只是为了说明概括。
请注意,将NumberSet#process
概括为reject
很容易,现在,NumberSet#process
和process(sf,f,o)
提供过滤器,sf
将是f
类的实例,它指定要发送到已过滤的子集合o
的proc,以使用块(Operation
,@arr
等调用Enumerable方法)。