Ruby中的过滤器联盟

时间:2014-10-22 19:47:04

标签: ruby class filter

我设计了一个NumberSet类,它包含一个数组,我必须在其上实现某些过滤器,我将其设计为类。代码是:

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 && number<0)
  return true if(@sign==:positive && number>0)
  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

一切运作良好,但我还必须定义&|运算符,使它们像交集和并集一样工作,这意味着&应该只获得满足所有过滤器和满足至少一个过滤器的|个数字。

另外,语法

numbers[SignFilter.new(:non_negative) & Filter.new { |number| number.even? }]

必须有效。

如何定义它们才能正常工作?


要回答一些评论,我正在寻找一种让操作符&|以我想要的方式工作的方法。问题不在于如何编写语法,而是defend之间的代码应该是什么。

4 个答案:

答案 0 :(得分:0)

您可以像任何其他方法一样定义它们。我只是试着这个例子:

class Adder
    def &(number_to_add)
        number_to_add + 20
    end
end

a = Adder.new
a & 20
#=> 40

答案 1 :(得分:0)

就像一张纸条,因为这看起来像是气味:

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?方法)或单独定义方法。我知道这不是你的实际问题的答案,我只是喜欢干净的代码。 :)

答案 2 :(得分:0)

这是值得冥想的事情......

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看到的最终值将为true,将返回。如果第一个失败,||将告诉Ruby检查下一个,并在链上。

这模仿了原始代码的行为,但两者都存在问题。在成功的结果中,返回true。失败将是零。这是你想要的,或者你想要返回false,使方法只返回true / false?在Ruby中,nil是一个“假”值,因此它的工作方式相同,但为了保持一致性,您可能只想返回true / false。

此外,作为编码式推荐,请在运算符之间使用空格。

@sign==:negative && number<0

不像

那样可读
@sign == :negative && number < 0

在调试时或将代码传递给其他人进行维护之后,可读性非常重要。人们喜欢说他们稍后会修复它,但后来,代码保持不变并被投入生产,等待在凌晨3点激怒一些可怜的灵魂。

答案 3 :(得分:0)

这样的事情怎么样?

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