Ruby中的filter联盟
我设计了一个NumberSet类,它包含一个数组,我必须在其上实现某些filter,我将其设计为类。 代码是:
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 def [] (sito) @arr.select{|number| sito.filter(number)} end end class Filter attr_reader :filter def initialize &block @filter = block end def filter number @filter.call(number) end end class SignFilter def initialize(sign) @sign = sign end def filter number return true if(@sign==:negative && number0) return true if(@sign==:nonnegative && number >= 0) return true if(@sign==:nonpositive && number <= 0) end end class TypeFilter def initialize(sign) @sign = sign end def filter number return true if (@sign==:complex && number.is_a?(Complex) == true) return true if (@sign==:integer && number.is_a?(Integer) == true) return true if (@sign==:real && (number.is_a?(Rational) == true || number.is_a?Float) == true)) end end
一切运作良好,但我还要定义&
和|
运算符使它们像交集和并集一样工作,这意味着&
应该只获得满足所有filter和|
满足至少一个filter的数字。
另外,语法
numbers[SignFilter.new(:non_negative) & Filter.new { |number| number.even? }]
必须有效。
如何定义它们以使它们正常工作?
为了回答一些评论,我正在寻找一种方法来制作运营商&
, |
以我想要的方式工作。 问题不在于如何编写语法,而是def
和end
之间的代码应该是什么。
您可以像任何其他方法一样定义它们。 我只是试着这个例子:
class Adder def &(number_to_add) number_to_add + 20 end end a = Adder.new a & 20 #=> 40
就像一张纸条,因为这看起来像是气味:
def filter number return true if(@sign==:negative && number<0) return true if(@sign==:positive && number>0) return true if(@sign==:nonnegative && number >= 0) return true if(@sign==:nonpositive && number <= 0) end
为什么试试这个:
class SignFilter @@signs = {negative: "<", positive: ">", nonnegative: ">=", nonpositive: "<="} @@signs.each do |meth,sign| define_method meth do |number| number.send(sign,0) end end def initialize(sign) @sign = sign end def filter(number) self.public_send(@sign,number) end end
您可以使用TypeFilter执行相同操作(作为提示Numeric
具有#real?
方法)或单独定义方法。 我知道这不是你的实际问题的答案,我只是喜欢干净的代码。 🙂
这是冥想的东西……
def filter number return true if(@sign==:negative && number<0) return true if(@sign==:positive && number>0) return true if(@sign==:nonnegative && number >= 0) return true if(@sign==:nonpositive && number <= 0) end
可以写成:
def filter number ( @sign == :negative && number < 0 ) || ( @sign == :positive && number > 0 ) || ( @sign == :nonnegative && number >= 0 ) || ( @sign == :nonpositive && number <= 0 ) end
为什么? 因为每个测试都返回true或false。 如果一个返回true,则没有其他人通过||
加入 将进行测试,因为||
短路,Ruby看到的最终值将是真的,将返回。 如果第一个失败, ||
将告诉Ruby检查下一个,并在链上。
这模仿了原始代码的行为,但两者都存在问题。 在成功的结果中,返回true。 失败将是零。 这是你想要的,还是你想要返回false使方法只返回true / false? 在Ruby中,nil是一个“假”值,因此它的工作方式相同,但为了保持一致性,您可能只想返回true / false。
此外,作为编码式推荐,请在运算符之间使用空格。
@sign==:negative && number<0
不像是那样可读
@sign == :negative && number < 0
在调试时或将代码传递给其他人进行维护之后,可读性非常重要。 人们喜欢说他们以后会修复它,但后来,代码保持不变并被投入生产,等待在凌晨3点激怒一些可怜的灵魂。
这样的事怎么样?
class Filter def initialize(&filter_block) @filter_block = filter_block end def filter(number) @filter_block.call(number) end def &(other) CompositeFilterAND.new(self, other) end def |(other) CompositeFilterOR.new(self, other) end end class CompositeFilterAND attr_accessor :left, :right def initialize(left, right) @left, @right = left, right end def filter(number) @left.filter(number) && @right.filter(number) # This is the magic. end end class CompositeFilterOR attr_accessor :left, :right def initialize(left, right) @left, @right = left, right end def filter(number) @left.filter(number) || @right.filter(number) # And this. end end
- Rails:如何迁移我添加了:belongs_to关系的数据库?
- Devise中的NoMethodError :: SessionsController#在使用“after_sign_in_path_for(resource)”时创建