如何组合过滤来过滤ruby中的列表?

时间:2012-10-30 10:43:46

标签: ruby-on-rails ruby lambda closures proc

我正在尝试在我的一个小项目中实施按标准过滤的方法。我有一个Filter类,其中我有名称,年份,流派的过滤器。例如:

Filter.new.name("The Shawshank Redemption")
Filter.new.year("1994")
Filter.new.genre("drama")

我还有一个电影列表,每个电影都是一个具有方法名称,年份和流派的对象。我希望能够做到以下几点(MoviesContainer只是一个有@movies列表的类):

MoviesContainer.filter Filter.new.name("The Godfather") & Filter.new.year("1972") | Filter.year("1974")

我很容易超载|,&而且!我的Filter类中的运算符,但我不知道如何组合过滤器对象,以便它们成为我可以传递给过滤器的一个对象。 我很乐意接受任何想法。 :)

到目前为止,我最好的想法是为每个Filter.new创建一个proc,然后将它们组合在&,|中而且!方法,但我不知道如何。我认为这样的事情可行,但事实并非如此:D

proc { |movie| proc { |movie| movie.name == "The Godfather" } && proc { |movie| movie.year== "1972" }

然后用每个@movies项调用它。 你能帮我解决一下这个组合过程的事情,或者提出一个更好的解决方案。谢谢。

1 个答案:

答案 0 :(得分:0)

也许是这样的?

class Filter
  attr_accessor :proc
  class <<self; alias :old_new :new end
  def self.new attribute, value
    old_new.tap{|f| f.proc = ->x{x.send(attribute) == value}}
  end
  def & other
    self.class.old_new.tap{|f| f.proc = ->x{proc.call(x) && other.proc.call(x)}}
  end
  def | other
    self.class.old_new.tap{|f| f.proc = ->x{proc.call(x) || other.proc.call(x)}}
  end
  def !
    self.class.old_new.tap{|f| f.proc = ->x{!proc.call(x)}}
  end
end

class Movie
  attr_accessor :name, :year, :genre
end

MoviesContainer = [
  Movie.new.tap{|m| m.name = "The Godfather"; m.year = "1972"},
  Movie.new
]

module Enumerable
  def filter f
    select(&f.proc)
  end
end

filter1 = Filter.new(:name, "The Godfather")
filter2 = Filter.new(:year, "1972")
filter3 = Filter.new(:year, "1974")

MoviesContainer.filter(filter1 & filter2 | filter3)
# => [#<Movie:0x000000017dba08 @name="The Godfather", @year="1972">]