Class: WeightedListRank::RankingContext

Inherits:
Object
  • Object
show all
Defined in:
lib/weighted_list_rank/context.rb

Overview

RankingContext is responsible for applying a ranking strategy to a collection of lists and their items. It aggregates scores for each item across all lists, based on the provided strategy.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(strategy = Strategies::Exponential.new, list_count_penalties: {}) ⇒ RankingContext

Initializes a new RankingContext with an optional ranking strategy and list count penalties.

Parameters:

  • strategy (Strategy) (defaults to: Strategies::Exponential.new)

    the strategy to use for ranking items, defaults to Strategies::Exponential.

  • list_count_penalties (Hash) (defaults to: {})

    hash mapping list counts to penalty percentages, defaults to empty hash.



12
13
14
15
# File 'lib/weighted_list_rank/context.rb', line 12

def initialize(strategy = Strategies::Exponential.new, list_count_penalties: {})
  @strategy = strategy
  @list_count_penalties = list_count_penalties
end

Instance Attribute Details

#list_count_penaltiesObject (readonly)

@strategy: The strategy used for calculating scores. @list_count_penalties: Hash mapping list counts to penalty percentages (e.g., => 0.50, 2 => 0.25)



7
8
9
# File 'lib/weighted_list_rank/context.rb', line 7

def list_count_penalties
  @list_count_penalties
end

#strategyObject (readonly)

@strategy: The strategy used for calculating scores. @list_count_penalties: Hash mapping list counts to penalty percentages (e.g., => 0.50, 2 => 0.25)



7
8
9
# File 'lib/weighted_list_rank/context.rb', line 7

def strategy
  @strategy
end

Instance Method Details

#rank(lists) ⇒ Array<Hash>

Ranks items across multiple lists according to the strategy's score calculation.

Parameters:

  • lists (Array<List>)

    an array of List objects to be ranked.

Returns:

  • (Array<Hash>)

    a sorted array of item scores, with each item's details including ID, score details, and total score.



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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/weighted_list_rank/context.rb', line 20

def rank(lists)
  items = {}

  # Strategies subclassing Strategy always have this; the fallback covers
  # duck-typed strategies that only define #calculate_score.
  batch_capable = strategy.respond_to?(:calculate_scores)

  lists.each do |list|
    list_items = list.items
    scores = if batch_capable
      strategy.calculate_scores(list)
    else
      list_items.map { |item| strategy.calculate_score(list, item) }
    end

    list_id = list.id
    weight = list.weight

    list_items.each_with_index do |item, index|
      score = scores[index]
      details = (items[item.id] ||= {list_details: [], total_score: 0})
      details[:list_details] << {list_id: list_id, score: score, weight: weight, score_penalty: item.score_penalty}
      details[:total_score] += score
    end
  end

  apply_penalties = !list_count_penalties.empty?

  # Convert hash to a formatted array
  formatted_items = items.map do |id, details|
    list_details = details[:list_details]
    total_score = details[:total_score]

    # Apply list count penalties if configured
    if apply_penalties && (penalty = list_count_penalties[list_details.length])
      total_score *= (1 - penalty)
    end

    {
      id: id,
      # Sort the score_details array by score in descending order before including it
      score_details: list_details.sort_by { |detail| -detail[:score] },
      total_score: total_score
    }
  end

  # Sort the array by total_score in descending order
  formatted_items.sort_by { |item| -item[:total_score] }
end