Ruby 배열에서 평균을 만들려면 어떻게합니까?
배열에서 평균을 어떻게 구할 수 있습니까?
배열이있는 경우 :
[0,4,8,2,5,0,2,6]
평균화하면 3.375가 표시됩니다.
감사!
이 시도:
arr = [5, 6, 7, 8]
arr.inject{ |sum, el| sum + el }.to_f / arr.size
=> 6.5
.to_f
정수 나누기의 문제를 피하기 위해을 참고하십시오 . 당신은 또한 할 수 있습니다 :
arr = [5, 6, 7, 8]
arr.inject(0.0) { |sum, el| sum + el } / arr.size
=> 6.5
Array
다른 주석 작성자가 제안한대로 이를 정의 할 수 있지만 정수 나누기를 피해야합니다. 그렇지 않으면 결과가 잘못 될 수 있습니다. 또한 이것은 일반적으로 가능한 모든 요소 유형에 적용 할 수있는 것은 아닙니다 (평균은 평균을 내릴 수있는 항목에만 의미가 있습니다). 그러나 그 길을 가고 싶다면 이것을 사용하십시오 :
class Array
def sum
inject(0.0) { |result, el| result + el }
end
def mean
sum / size
end
end
inject
전에 보지 못했다면 , 그것은 마술처럼 보이지 않습니다. 각 요소를 반복 한 다음 누산기 값을 적용합니다. 그런 다음 누산기가 다음 요소로 전달됩니다. 이 경우 누적 기는 단순히 이전의 모든 요소의 합을 반영하는 정수입니다.
편집자 : Commenter Dave Ray는 훌륭한 개선을 제안했습니다.
편집 : Commenter Glenn Jackman의 제안은을 사용하여 arr.inject(:+).to_f
훌륭하지만 어떤 일이 일어나고 있는지 모른다면 약간 영리합니다. 는 :+
심볼이고; 주입하도록 전달되면 누적 기 값에 대해 기호로 명명 된 메소드 (이 경우 추가 연산)가 각 요소에 적용됩니다.
a = [0,4,8,2,5,0,2,6]
a.instance_eval { reduce(:+) / size.to_f } #=> 3.375
사용하지 않는 버전은 다음과 같습니다 instance_eval
.
a = [0,4,8,2,5,0,2,6]
a.reduce(:+) / a.size.to_f #=> 3.375
가장 간단한 대답은
list.reduce(:+).to_f / list.size
나는 Math.average (values)를 원했지만 그런 행운은 없습니다.
values = [0,4,8,2,5,0,2,6]
average = values.sum / values.size.to_f
Ruby 버전> = 2.4에는 Enumerable # sum 메소드가 있습니다.
부동 소수점 평균을 얻으려면 Integer # fdiv를 사용할 수 있습니다
arr = [0,4,8,2,5,0,2,6]
arr.sum.fdiv(arr.size)
# => 3.375
이전 버전의 경우 :
arr.reduce(:+).fdiv(arr.size)
# => 3.375
최고 솔루션의 일부 벤치마킹 (가장 효율적인 순서) :
큰 배열 :
array = (1..10_000_000).to_a
Benchmark.bm do |bm|
bm.report { array.instance_eval { reduce(:+) / size.to_f } }
bm.report { array.sum.fdiv(array.size) }
bm.report { array.sum / array.size.to_f }
bm.report { array.reduce(:+).to_f / array.size }
bm.report { array.reduce(:+).try(:to_f).try(:/, array.size) }
bm.report { array.inject(0.0) { |sum, el| sum + el }.to_f / array.size }
bm.report { array.reduce([ 0.0, 0 ]) { |(s, c), e| [ s + e, c + 1 ] }.reduce(:/) }
end
user system total real
0.480000 0.000000 0.480000 (0.473920)
0.500000 0.000000 0.500000 (0.502158)
0.500000 0.000000 0.500000 (0.508075)
0.510000 0.000000 0.510000 (0.512600)
0.520000 0.000000 0.520000 (0.516096)
0.760000 0.000000 0.760000 (0.767743)
1.530000 0.000000 1.530000 (1.534404)
작은 배열 :
array = Array.new(10) { rand(0.5..2.0) }
Benchmark.bm do |bm|
bm.report { 1_000_000.times { array.reduce(:+).to_f / array.size } }
bm.report { 1_000_000.times { array.sum / array.size.to_f } }
bm.report { 1_000_000.times { array.sum.fdiv(array.size) } }
bm.report { 1_000_000.times { array.inject(0.0) { |sum, el| sum + el }.to_f / array.size } }
bm.report { 1_000_000.times { array.instance_eval { reduce(:+) / size.to_f } } }
bm.report { 1_000_000.times { array.reduce(:+).try(:to_f).try(:/, array.size) } }
bm.report { 1_000_000.times { array.reduce([ 0.0, 0 ]) { |(s, c), e| [ s + e, c + 1 ] }.reduce(:/) } }
end
user system total real
0.760000 0.000000 0.760000 (0.760353)
0.870000 0.000000 0.870000 (0.876087)
0.900000 0.000000 0.900000 (0.901102)
0.920000 0.000000 0.920000 (0.920888)
0.950000 0.000000 0.950000 (0.952842)
1.690000 0.000000 1.690000 (1.694117)
1.840000 0.010000 1.850000 (1.845623)
class Array
def sum
inject( nil ) { |sum,x| sum ? sum+x : x }
end
def mean
sum.to_f / size.to_f
end
end
[0,4,8,2,5,0,2,6].mean
공공 오락을위한 또 다른 해결책 :
a = 0, 4, 8, 2, 5, 0, 2, 6
a.reduce [ 0.0, 0 ] do |(s, c), e| [ s + e, c + 1 ] end.reduce :/
#=> 3.375
제로 문제로 나눗셈을 해결하는 무언가를 경쟁으로 가져 오겠습니다.
a = [1,2,3,4,5,6,7,8]
a.reduce(:+).try(:to_f).try(:/,a.size) #==> 4.5
a = []
a.reduce(:+).try(:to_f).try(:/,a.size) #==> nil
그러나 "시도"는 Rails 도우미라는 것을 인정해야합니다. 그러나 이것을 쉽게 해결할 수 있습니다.
class Object;def try(*options);self&&send(*options);end;end
class Array;def avg;reduce(:+).try(:to_f).try(:/,size);end;end
BTW : 빈 목록의 평균이 0이 아니라고 생각합니다. 아무것도 아닌 평균은 0이 아닌 아무것도 아닙니다. 따라서 예상되는 동작입니다. 그러나 다음과 같이 변경하면
class Array;def avg;reduce(0.0,:+).try(:/,size);end;end
the result for empty Arrays won't be an exception as I had expected but instead it returns NaN... I've never seen that before in Ruby. ;-) Seems to be a special behavior of the Float class...
0.0/0 #==> NaN
0.1/0 #==> Infinity
0.0.class #==> Float
what I don't like about the accepted solution
arr = [5, 6, 7, 8]
arr.inject{ |sum, el| sum + el }.to_f / arr.size
=> 6.5
is that it does not really work in a purely functional way. we need a variable arr to compute arr.size at the end.
to solve this purely functionally we need to keep track of two values: the sum of all elements, and the number of elements.
[5, 6, 7, 8].inject([0.0,0]) do |r,ele|
[ r[0]+ele, r[1]+1 ]
end.inject(:/)
=> 6.5
Santhosh improved on this solution: instead of the argument r being an array, we could use destructuring to immediatly pick it apart into two variables
[5, 6, 7, 8].inject([0.0,0]) do |(sum, size), ele|
[ sum + ele, size + 1 ]
end.inject(:/)
if you want to see how it works, add some puts:
[5, 6, 7, 8].inject([0.0,0]) do |(sum, size), ele|
r2 = [ sum + ele, size + 1 ]
puts "adding #{ele} gives #{r2}"
r2
end.inject(:/)
adding 5 gives [5.0, 1]
adding 6 gives [11.0, 2]
adding 7 gives [18.0, 3]
adding 8 gives [26.0, 4]
=> 6.5
We could also use a struct instead of an array to contain the sum and the count, but then we have to declare the struct first:
R=Struct.new(:sum, :count)
[5, 6, 7, 8].inject( R.new(0.0, 0) ) do |r,ele|
r.sum += ele
r.count += 1
r
end.inject(:/)
Don't have ruby on this pc, but something to this extent should work:
values = [0,4,8,2,5,0,2,6]
total = 0.0
values.each do |val|
total += val
end
average = total/values.size
a = [0,4,8,2,5,0,2,6]
sum = 0
a.each { |b| sum += b }
average = sum / a.length
a = [0,4,8,2,5,0,2,6]
a.empty? ? nil : a.reduce(:+)/a.size.to_f
=> 3.375
Solves divide by zero, integer division and is easy to read. Can be easily modified if you choose to have an empty array return 0.
I like this variant too, but it's a little more wordy.
a = [0,4,8,2,5,0,2,6]
a.empty? ? nil : [a.reduce(:+), a.size.to_f].reduce(:/)
=> 3.375
arr = [0,4,8,2,5,0,2,6] average = arr.inject(&:+).to_f / arr.size => 3.375
This method can be helpful.
def avg(arr)
val = 0.0
arr.each do |n|
val += n
end
len = arr.length
val / len
end
p avg([0,4,8,2,5,0,2,6])
Add Array#average
.
I was doing the same thing quite often so I thought it was prudent to just extend the Array
class with a simple average
method. It doesn't work for anything besides an Array of numbers like Integers or Floats or Decimals but it's handy when you use it right.
I'm using Ruby on Rails so I've placed this in config/initializers/array.rb
but you can place it anywhere that's included on boot, etc.
config/initializers/array.rb
class Array
# Will only work for an Array of numbers like Integers, Floats or Decimals.
#
# Throws various errors when trying to call it on an Array of other types, like Strings.
# Returns nil for an empty Array.
#
def average
return nil if self.empty?
self.sum / self.size
end
end
You could try something like the following:
2.0.0-p648 :009 > a = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
2.0.0-p648 :010 > (a.sum/a.length).to_f
=> 3.0
[1,2].tap { |a| @asize = a.size }.inject(:+).to_f/@asize
Short but using instance variable
참고URL : https://stackoverflow.com/questions/1341271/how-do-i-create-an-average-from-a-ruby-array
'IT story' 카테고리의 다른 글
node.js 전역 변수? (0) | 2020.05.07 |
---|---|
NSUserDefaults-키가 있는지 확인하는 방법 (0) | 2020.05.07 |
왜 C가 그렇게 빠르며 다른 언어가 그렇게 빠르거나 빠르지 않습니까? (0) | 2020.05.07 |
PHP에서 이메일 주소를 확인하는 방법 (0) | 2020.05.07 |
fgets () 입력에서 후행 줄 바꿈 문자 제거 (0) | 2020.05.07 |