【问题标题】:How to filter list on multiple criteria in ruby?如何在 ruby​​ 中过滤多个条件的列表?
【发布时间】:2012-10-18 03:22:18
【问题描述】:

我想创建一个过滤器类,其中包含三种方法:namegenreyear。我想过滤一个电影列表,其中每个对象都有一个nametitle 和一个year,在多个条件下。

我不知道该怎么做。例如:

Filter.name("Batman") & Filter.genre("Drama") | !Filter.year(2001)

我试图将过滤器字段保留在[name => batman, genre=>drama] 列表中,等等,但操作符(尤其是or (|))正在困扰我。

我接受任何想法。

【问题讨论】:

  • 我只想通过重载 &, | 来制作一个过滤器对象和 !运营商。
  • “重载 &、| 和 ! 运算符”是什么意思?您的示例代码不会重载它们,只是错误地使用它们。

标签: ruby filter conditional-statements


【解决方案1】:

试试这个:

让 ary 包含对象列表

ary.select{|obj| obj.name == 'batman' && obj.genre == 'drama' || obj.year != 2001}

我假设您在列表中有对象,请注意 && 和 ||运算符优先级

或者你期待这个?

class Filter
  def self.search_by(ary, name, genre, year)
    ary.select{|obj| obj.name == name && obj.genre == genre || obj.year != year}
  end
end

ary = all_films # assume function returns all films
Filter.search_by(ary, 'batman', 'drama', 2001)

【讨论】:

  • 也可以使用select!修改已有的Array
  • 我只想创建一个包含所有子过滤器的过滤器对象。在上面的示例中,三个过滤器应该只成为一个过滤器对象。另外,我想重载运算符 |和&。
  • 这里没有 OR。如果我想要 name='batman' 怎么办 | (或)年='2001'?
【解决方案2】:

您想要的功能自然适合 Array 继承的 Enumerable 的选择。

因为您在谈论一个列表,AKA,数组,所以很自然地适合使用 select 来确定您的电影是否符合您的标准,而不是将它们传递给方法。

单独的 Filter 类也不适合 Ruby 方式。考虑为您的电影列表子类化 Array,并添加一个将您的条件作为参数的过滤器方法。

这是我编写该功能的方式,但以我认为更像 Ruby 的方式编写:

require 'pp'

class Movies < Array

  def initialize(*movies)
    super(movies)
  end

  def filter(criteria={})
    self.select{ |m| 
      criteria.all?{ |c, v| 
        m.send(c, v) 
      }
    }
  end
end

class Movie

  def initialize(attributes={})
    @movie = attributes
  end

  def name(t)
    case t
    when Regexp
      @movie[:name][t]
    when String
      @movie[:name] == t
    end
  end

  def genre(g)
    @movie[:genre] == g
  end

  def year(y)
    @movie[:year] == y
  end

end

movies = Movies.new(
  Movie.new(name: 'Batman', genre: 'Drama', year: 2001),
  Movie.new(name: 'The Shawshank Redemption', genre: 'Drama', year: 1994),
  Movie.new(name: 'Raiders of the Lost Ark', genre: 'Action', year: 1981)
)

pp movies.filter(year: 1981)
pp movies.filter(genre: 'Drama', year: 2001)
pp movies.filter(name: /redemption/i)

我为 Movie 类使用了哈希,因为它更快。这也是一种更脏的方式,但它确实有效。

这是运行代码的输出:

[#<Movie:0x007ff7b191ffb8
  @movie={:name=>"Raiders of the Lost Ark", :genre=>"Action", :year=>1981}>]
[#<Movie:0x007ff7b1920260
  @movie={:name=>"Batman", :genre=>"Drama", :year=>2001}>]
[#<Movie:0x007ff7b19200d0
  @movie={:name=>"The Shawshank Redemption", :genre=>"Drama", :year=>1994}>]

过滤电影的实际流程适合我们通常编写 Ruby 代码的方式。它可以做得更好,但这是一个开始。

【讨论】:

    【解决方案3】:

    | 是二元或运算符

    || 是逻辑或运算符。如果两个操作数中的任何一个不为零,则条件为真。

    所以你需要采取后者,

    像这样:

    Filter.name("Batman") && Filter.genre("Drama") || !Filter.year(2001)
    

    请参阅http://www.tutorialspoint.com/ruby/ruby_operators.htm 了解更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-16
      • 2013-07-21
      • 1970-01-01
      • 2023-03-14
      • 2023-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多