Module: WeightedAverage::ArelSelectManagerInstanceMethods

Defined in:
lib/weighted_average/arel_select_manager_instance_methods.rb

Instance Method Summary collapse

Instance Method Details

#weighted_average(data_column_names, options = {}) ⇒ Float?

Calculate the weighted average of column(s).

Examples:

Weighted average of load factor in flight stage data

Arel::Table.new(:flight_segments).weighted_average(:load_factor, :weighted_by => :passengers)

Parameters:

  • data_column_names (Symbol, Array<Symbol>)

    One or more column names whose average should be calculated. Added together before being multiplied by the weighting if more than one.

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

Options Hash (options):

  • :weighted_by (Symbol)

    The name of the weighting column if it’s not :weighting (the default)

  • :disaggregate_by (Symbol)

    The name of a column to disaggregate by. Usually not necessary.

Returns:

  • (Float, nil)

See Also:



17
18
19
20
# File 'lib/weighted_average/arel_select_manager_instance_methods.rb', line 17

def weighted_average(data_column_names, options = {})
  weighted_average = @engine.connection.select_value(weighted_average_relation(data_column_names, options).to_sql)
  weighted_average.nil? ? nil : weighted_average.to_f
end

#weighted_average_relation(data_column_names, options = {}) ⇒ Arel::SelectManager

In case you want to get the relation and/or the SQL of the calculation query before actually runnnig it.

Examples:

Get the SQL

Arel::Table.new(:flight_segments).weighted_average_relation(:load_factor, :weighted_by => :passengers).to_sql

Returns:

  • (Arel::SelectManager)

    A relation you can play around with.



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
69
# File 'lib/weighted_average/arel_select_manager_instance_methods.rb', line 28

def weighted_average_relation(data_column_names, options = {})
  left = self.source.left

  weighted_by_column = case options[:weighted_by]
  when Arel::Attribute
    options[:weighted_by]
  when Symbol, String
    left[options[:weighted_by]]
  when NilClass
    left[DEFAULT_WEIGHTED_BY_COLUMN_NAME]
  else
    raise ArgumentError, ":weighted_by => #{options[:weighted_by].inspect} must be a column on #{left.inspect}"
  end
  
  disaggregate_by_column = if options[:disaggregate_by]
    left[options[:disaggregate_by]]
  end

  data_columns = ::Array.wrap(data_column_names).map do |data_column_name|
    left[data_column_name]
  end

  if disaggregate_by_column
    self.projections = [Arel::Nodes::Division.new(Arel::Nodes::Sum.new(weighted_by_column * (data_columns.inject(:+)) / disaggregate_by_column * 1.0), Arel::Nodes::Sum.new([weighted_by_column]))]
  else
    self.projections = [Arel::Nodes::Division.new(Arel::Nodes::Sum.new(weighted_by_column * (data_columns.inject(:+)) * 1.0), Arel::Nodes::Sum.new([weighted_by_column]))]
  end

  data_columns_not_eq_nil = data_columns.inject(nil) do |memo, data_column|
    if memo
      memo.and(data_column.not_eq(nil))
    else
      data_column.not_eq(nil)
    end
  end

  if disaggregate_by_column
    where data_columns_not_eq_nil.and(weighted_by_column.gt(0)).and(disaggregate_by_column.gt(0))
  else
    where data_columns_not_eq_nil.and(weighted_by_column.gt(0))
  end
end