Reputation:
I want to make a filter class in which I have three methods: name
, genre
, and year
. I want to filter a list of movies, in which every object has a name
, title
and a year
, on multiple criteria.
I can't figure out how to do this. For example:
Filter.name("Batman") & Filter.genre("Drama") | !Filter.year(2001)
I tried to keep the filter fields in a list [name => batman, genre=>drama]
, and so on, but the operators (especially or
(|
)) are bugging me.
I'm accepting any ideas.
Upvotes: 1
Views: 7739
Reputation: 160551
The functionality you want fits naturally into Enumerable's select, which Array inherits.
Because you're talking about a list, AKA, array, it's a natural fit to use select to determine whether your movies meet your criteria by building upon that, instead of passing them into a method.
A separate Filter class will not fit the Ruby-way as well. Consider sub-classing Array for your movie list, and adding a filter method that takes your criteria as parameters.
Here's how I'd write that functionality, but doing it in a way I consider more Ruby-like:
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)
I used a hash for the Movie class, because it's quicker. It's also a dirtier way to go, but it works.
Here's the output of running the code:
[#<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}>]
The actual flow of filtering the movies fits into how we normally write Ruby code. It could be done even better, but that's a start.
Upvotes: 5
Reputation: 1556
Try this:
let ary contains the list of objects
ary.select{|obj| obj.name == 'batman' && obj.genre == 'drama' || obj.year != 2001}
I have assumed that you have objects in a list, watch out for the && and || operator pririties
Or you expecting this?
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)
Upvotes: 8
Reputation: 710
|
is a binary OR operator
||
is the logical OR Operator. If any of the two operands are non zero then then condition becomes true.
So you need to take the latter,
Like this:
Filter.name("Batman") && Filter.genre("Drama") || !Filter.year(2001)
See http://www.tutorialspoint.com/ruby/ruby_operators.htm for more info.
Upvotes: 1