Reputation: 87
I'm trying to turn 2 lines of ruby code into 1. For example:
def average(numbers)
result = numbers.compact
numbers.reduce(+) / numbers.length
end
I've been looking through array methods and can't find an appropriate one to turn this function into a one-liner. I had hoped something like this would work:
def average(numbers)
numbers.compact.<tap or another method> { |arr| arr.reduce(+) / arr.length }
end
Basically, I'm modifying the array (in the example I have to call compact to rid nil
values), so I don't have access to the array variable, and I don't want an iterator, because I don't want to call reduce(+)
and length
on individual elements of the array.
Does anyone have an idea of methods I could look into?
Upvotes: 0
Views: 56
Reputation: 110685
I believe you mean for your method to be the following (reduce(:+)
, not reduce(+)
and use result
rather than numbers
in the second line).
def average(numbers)
result = numbers.compact
result.reduce(:+) / result.length
end
average [1,2,3]
#=> 2
If you wish the average to be a float, change the second line to
result.reduce(0.0, :+) / result.length
There are various ways to combine the two lines of the method, but I don't prefer any of them to the above. Here are a few. (I don't see how Object#tap could be used here.)
numbers.compact.reduce(:+) / numbers.compact.length
(result = numbers.compact).reduce(:+) / result.compact.length
numbers.map(&:to_i).reduce(:+) / numbers.compact.length
Note that, even if numbers
can be mutated, one cannot write
numbers.compact!.reduce(:+) / numbers.length
because numbers.compact!
returns nil
if numbers
contains no nil
elements.
In Ruby v2.4+ you can use Array#sum:
result.sum / result.length
Upvotes: 2
Reputation: 6076
You could change the way you call average
def average(numbers)
numbers.reduce(:+) / numbers.length
end
average(num_array.compact)
Upvotes: 0