IT

루비 배열에서 평균을 만들려면 어떻게 해야 합니까?

itgroup 2023. 6. 7. 22:31
반응형

루비 배열에서 평균을 만들려면 어떻게 해야 합니까?

배열에서 평균을 찾는 방법은 무엇입니까?

배열이 있는 경우:

[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이전에는, 그것이 보이는 것만큼 마법적이지 않습니다.각 요소에 대해 반복된 다음 축전지 값을 적용합니다.그런 다음 축전지가 다음 요소로 전달됩니다.이 경우, 우리의 축전지는 단순히 이전의 모든 요소들의 합을 반영하는 정수입니다.

편집: 해설자 데이브 레이는 멋진 개선안을 제안했습니다.

편집: 해설자 글렌 잭맨의 제안, 사용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

저는 수학.평균(값)을 기대하고 있었지만, 그런 행운은 없었습니다.

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)

배열을 반복할 필요 없이(예: 한 줄기에 완벽함):

[1, 2, 3, 4].then { |a| a.sum.to_f / a.size }
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 = [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

하지만 "노력"이 레일즈의 조력자라는 것은 인정해야 합니다.하지만 이 문제는 쉽게 해결할 수 있습니다.

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이 아닌 0의 평균은 아무것도 아닙니다.이것이 예상되는 행동입니다.그러나 다음으로 변경하는 경우:

class Array;def avg;reduce(0.0,:+).try(:/,size);end;end

빈 어레이의 결과도 예외는 아니지만 NaN을 반환합니다...루비에서 처음 보는 거예요 ;-) 플로트 클래스의 특별한 행동인 것 같아요...

0.0/0 #==> NaN
0.1/0 #==> Infinity
0.0.class #==> Float

대중의 즐거움을 위한 또 다른 해결책:

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

승인된 해결책에 대해 내가 좋아하지 않는 것

arr = [5, 6, 7, 8]
arr.inject{ |sum, el| sum + el }.to_f / arr.size
=> 6.5

순수하게 기능적인 방식으로 작동하지 않는다는 것입니다. 마지막에 ar.size를 계산하려면 변수 ar가 필요합니다.

이것을 순수하게 기능적으로 해결하기 위해 우리는 두 가지 값, 즉 모든 요소의 합과 요소의 수를 추적할 필요가 있습니다.

[5, 6, 7, 8].inject([0.0,0]) do |r,ele|
    [ r[0]+ele, r[1]+1 ]
end.inject(:/)
=> 6.5   

Santhosh는 이 솔루션을 개선했습니다: 인수 r이 배열인 대신, 우리는 파괴를 사용하여 즉시 두 변수로 분리할 수 있습니다.

[5, 6, 7, 8].inject([0.0,0]) do |(sum, size), ele| 
   [ sum + ele, size + 1 ]
end.inject(:/)

작동 방식을 확인하려면 다음과 같이 입력합니다.

[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

또한 배열 대신 구조체를 사용하여 합계와 카운트를 포함할 수 있지만 먼저 구조체를 선언해야 합니다.

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(:/)

또 다른 간단한 솔루션

arr = [0,4,8,2,5,0,2,6]
arr.sum(0.0) / arr.size

원하는 대로 다음 솔루션 중 하나를 선택할 수 있습니다.

브루트 포스

[0,4,8,2,5,0,2,6].sum.to_f / [0,4,8,2,5,0,2,6].size.to_f

=> 3.375

방법

def avg(array)
  array.sum.to_f / array.size.to_f
end  

avg([0,4,8,2,5,0,2,6])
=> 3.375

원숭이 패치

class Array
  def avg
    sum.to_f / size.to_f
  end
end

[0,4,8,2,5,0,2,6].avg
=> 3.375

그러나 Array 클래스를 monkeypatch로 패치하는 것은 권장하지 않습니다. 이 작업은 위험하며 잠재적으로 시스템에 바람직하지 않은 영향을 미칠 수 있습니다.

우리의 이익을 위해 루비 언어는 이 문제를 극복할 수 있는 좋은 기능을 제공하는데, 이것은 루비에 원숭이 패치를 적용하는 안전한 방법입니다.

단순화하기 위해, 개선을 사용하여 원숭이 패치를 적용할 수 있습니다.Array및할 수 :) :) 에 대한 설명과 함께 사용할 수 있습니다.

작업 중인 클래스 내에서 세분화를 사용할 수 있으며 준비가 완료되었습니다.

세련됨

module ArrayRefinements
  refine Array do
    def avg
      sum.to_f / size.to_f
    end
  end
end

class MyClass
  using ArrayRefinements

  def test(array)
    array.avg
  end
end

MyClass.new.test([0,4,8,2,5,0,2,6])
=> 3.375

이 PC에는 루비가 없지만, 이 정도는 작동할 것입니다.

values = [0,4,8,2,5,0,2,6]
total = 0.0
values.each do |val|
 total += val
end

average = total/values.size

더하다Array#average.

을 꽤 하고 에 그냥 했습니다.Array 수업average. , 또는 와 같은 숫자 할 때 정수, 부동소수 또는 소수와 같은 숫자 배열 외에는 작동하지 않지만 올바르게 사용할 때 유용합니다.

저는 루비 온 레일즈를 사용하고 있기 때문에 이것을 배치했습니다.config/initializers/array.rb하지만 부츠 등에 포함된 모든 곳에 설치할 수 있습니다.

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.to_d / self.size
  end

end
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

0으로 나누기, 정수 나누기를 해결하고 읽기 쉽습니다.빈 배열이 0을 반환하도록 선택하면 쉽게 수정할 수 있습니다.

저도 이 변종을 좋아하지만, 좀 더 말이 많아요.

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

이 방법은 도움이 될 수 있습니다.

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])

print array.sum / array.count가 제가 한 방법입니다.

나는 정말로 정의하는 것을 좋아합니다.mean()내 코드가 더 표현력이 있도록 하는 방법.

나는 보통 무시하고 싶습니다.nil기본적으로, 제가 정의하는 것은 다음과 같습니다.

def mean(arr)
  arr.compact.inject{ |sum, el| sum + el }.to_f / arr.compact.size
end

mean([1, nil, 5])
=> 3.0

만약 당신이 그것을 유지하고 싶다면.nils, 둘 다 제거하기만 하면 됩니다..compacts의

.inject보다 훨씬 빠른 솔루션은 다음과 같습니다.

ar.sum(0.0) / ar.size

다음 문서를 참조하십시오. https://andycroll.com/ruby/calculate-a-mean-average-from-a-ruby-array/

[1,2].tap { |a| @asize = a.size }.inject(:+).to_f/@asize

짧지만 인스턴스 변수를 사용) 변수 사용

다음과 같은 방법을 사용할 수 있습니다.

a = [1,2,3,4,5]
# => [1, 2, 3, 4, 5]
(a.sum/a.length).to_f
# => 3.0

언급URL : https://stackoverflow.com/questions/1341271/how-do-i-create-an-average-from-a-ruby-array

반응형