Skip to content
Snippets Groups Projects
Commit e03eea71 authored by Mauricio Giacomini Girardello's avatar Mauricio Giacomini Girardello
Browse files

refactoring ranking module

decouple rater class from sort alg, create concrete classes for item, rated item and basic rater strategy
parent 2ece9bf1
No related branches found
No related tags found
No related merge requests found
# Use Example
### Input :
items = [Item.new("ax",1,1,1,["otherStuffA","lala",'a']),Item.new("bx",2,2,2,[1,2,3,"teste","lblb",'b']),Item.new("cx",1,1,99,[3,2,1,"teste","lclc",'c'])]
# Ranking docs
# Refactored
### Rank call :
```ruby
items = []
items << Ranking::Item.new("ax",1,1,1,["otherStuffA","lala",'a'])
items << Ranking::Item.new("bx",2,2,2,[1,2,3,"teste","lblb",'b'])
items << Ranking::Item.new("cx",1,1,99,[3,2,1,"teste","lclc",'c'])
Rater.new.sortByRate(items).each { |i| puts i }
###### OR
rater = Ranking::Rater.new(Ranking::Strategies::BasicRater.new(1000, 1, 100))
rater.sortByRate(items).each do |i|
p i.name
end
```
Rater.new( # Order of the arguments is important!
positionWeight = 1000,
useWeight = 1,
likeWeight = 100
).sortByRate(items).each { |i| puts i }
#### Return (output) :
## Output
- ordered array of Items, starting from the most ranked to the least
\ No newline at end of file
# This class represents an item of ranking
class Ranking::Item
# name = name of object
# views = view count
# downloads = download count
# likes = like count
# info = just for convinience of sorting it together, won't be touched
attr_accessor :name, :views, :downloads, :likes, :info
def initialize(name, views = 0, downloads = 0, likes = 0, info = nil)
@name = name
@views = views
@downloads = downloads
@likes = likes
@info = info
end
end
\ No newline at end of file
# Input: Array of struct Item (sorted by DB name matching)
# Output: Array of struct Item sorted by ranking
Item = Struct.new :name,:views,:downloads,:likes,:otherInfo # For interfacing
# name = name of object
# views = view count
# downloads = download count
# likes = like count
# otherInfo = Anything, just for convinience of sorting it together, won't be touched
class Rater #INTERFACE
def initialize positionWeight = nil, useWeight = nil, likeWeight = nil
@rater = BasicRater.new positionWeight, useWeight, likeWeight
end
def sortByRate items
@rater.sortByRate items
end
end
class BasicRater # Don't instanciate this directly, use Rater
RatedItem = Struct.new(:item,:rate)
def initialize positionWeight = nil, useWeight = nil, likeWeight = nil
@positionWeight = (positionWeight == nil ? 1000 : positionWeight)
@useWeight = (useWeight == nil ? 3 : useWeight)
@likeWeight = (likeWeight == nil ? 100 : likeWeight)
end
def rateItem item, inversePosition # Returns: RatedItem instance
positionRating = inversePosition * @positionWeight
useRating = (item.downloads < item.views ? item.downloads : item.views)*@useWeight
likeRating = item.likes * @likeWeight
rate = positionRating + useRating + likeRating
RatedItem.new( item, rate )
end
def sortByRate items
first = items.first
rest = items.drop(1)
rest.zip( rest.size.downto(1) )
.collect { |item,reverseIndex| self.rateItem( item, reverseIndex ) } # Returns RatedItem instance
.sort { |itemA,itemB| itemA.rate <=> itemB.rate }
.collect { |ri| ri.item }
.push( first )
.reverse # Best ranked comes first
end
end
# This class represents an item rated in ranking
# Have an association with a rank item
class Ranking::RatedItem
attr_accessor :item, :rate
def initialize(item, rate)
@item = item
@rate = rate
end
end
\ No newline at end of file
class Ranking::Rater
def initialize(rater_strategy)
@rater = rater_strategy
end
def sortByRate(items)
@rater.sortByRate items
end
end
\ No newline at end of file
class Ranking::Strategies::BasicRater < Ranking::Strategy
def sortByRate(items)
first = items.first
rest = items.drop(1)
rest.zip(rest.size.downto(1))
.collect { |item, reverseIndex| rateItem(item, reverseIndex) } # Returns RatedItem instance
.sort { |itemA, itemB| itemA.rate <=> itemB.rate }
.collect { |ri| ri.item }
.push(first)
.reverse # Best ranked comes first
end
private
def rateItem(item, inversePosition)
positionRating = inversePosition * @positionWeight
useRating = (item.downloads < item.views ? item.downloads : item.views) * @useWeight
likeRating = item.likes * @likeWeight
rate = positionRating + useRating + likeRating
build_rated_item item, rate
end
end
\ No newline at end of file
class Ranking::Strategy
def initialize(positionWeight = nil, useWeight = nil, likeWeight = nil)
@positionWeight = (positionWeight == nil ? 1000 : positionWeight)
@useWeight = (useWeight == nil ? 3 : useWeight)
@likeWeight = (likeWeight == nil ? 100 : likeWeight)
end
protected
def build_rated_item(item, rate)
Ranking::RatedItem.new(item, rate)
end
end
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment