Afonso Brandão
Afonso Brandão

Reputation: 1

How to create a function in Ruby that take a average of an array?

I tried something like this:

def average_array_float(&array)
  array.inject{ |sum, el| sum + el }.to_f / array.size
end

no success

array = [1, 2, 3]

def even_numbers(array)
  array.select { |num| num.even? }
end

p array.even_numbers

reply:

$ bundle exec ruby main.rb
Traceback (most recent call last):
main.rb:7:in `<main>': private method `even_numbers' called for [1, 2, 3]:Array (NoMethodError)
exit status 1

what i am doing wrong?

Upvotes: 0

Views: 52

Answers (1)

Stefan
Stefan

Reputation: 114128

You have to pass the array to the method:

def even_numbers(array)
  array.select { |num| num.even? }
end

array = [1, 2, 3, 4, 5, 6]
even_numbers(array)
#=> [2, 4, 6]

The NoMethodError in your example happens because if you define a method on the top-level, it becomes a private method of Object:

Object.private_methods
#=> [:initialize, :inherited, :method_added, :method_removed, :method_undefined,
#    :remove_const, :initialize_copy, :initialize_clone, :using, :public,
#    :ruby2_keywords, :protected, :private, :included, :extended, :prepended,
#    :even_numbers, :sprintf, :format, ...]
#    ^^^^^^^^^^^^^

And since array is an Object, it can access that method (privately).

If you really wanted to add the method to Array, you could open the corresponding class:

class Array
  def even_numbers
    select { |num| num.even? }
  end
end

Which gives you:

[1, 2, 3, 4, 5, 6].even_numbers
#=> [2, 4, 6]

However, although this works, it's not advised to alter objects that are not your own, let alone Ruby's core classes.


Regarding your other method, you could use sum and fdiv:

def average(array)
  array.sum.fdiv(array.size)
end

average([1, 2, 4])
#=> 2.3333333333333335

Or quo if you prefer a precise result:

def average(array)
  array.sum.quo(array.size)
end

average([1, 2, 4])
#=> (7/3)

Upvotes: 1

Related Questions