如何在ruby中筛选多个条件的列表?

How to filter list on multiple criteria in ruby?

我想创建一个filter类,其中有三个方法:namegenreyear。我想筛选一个电影列表,其中每个对象都有一个nametitleyear,有多种标准。

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

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

我试图将筛选字段保存在一个列表[name => batman, genre=>drama]中,等等,但是操作员(尤其是or(|)在窃听我。

我接受任何想法。


试试这个:

让ARY包含对象列表

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

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

或者你期待着呢?

1
2
3
4
5
6
7
8
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)


您想要的功能很自然地适合Enumerable的Select,它继承了哪个数组。

因为你说的是一个列表,也就是数组,用select来确定你的电影是否符合你的标准是很自然的,它是建立在这个基础上的,而不是传递给一个方法。

单独的过滤器类也不适合Ruby。考虑为电影列表子分类数组,并添加一个将条件作为参数的筛选方法。

下面是我编写这个功能的方法,但我认为这样做更像Ruby:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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)

我在电影课上用了一个哈希表,因为它更快。这也是一个更脏的方式,但它起作用。

下面是运行代码的输出:

1
2
3
4
5
6
[#<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代码的方式。它可以做得更好,但这是一个开始。


|是一个二进制或运算符。

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

所以你要拿后者,

这样地:

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

有关详细信息,请参阅http://www.tutorialspoint.com/ruby/ruby_operators.htm。