[ruby-on-rails] 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