루비 배열에서 평균을 만들려면 어떻게 해야 합니까?
배열에서 평균을 찾는 방법은 무엇입니까?
배열이 있는 경우:
[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
만약 당신이 그것을 유지하고 싶다면.nil
s, 둘 다 제거하기만 하면 됩니다..compact
s의
.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
'IT' 카테고리의 다른 글
Android Studio 4.2가 Gradle 표시줄에 서명 보고서를 표시하지 않음 (0) | 2023.06.07 |
---|---|
ARM 템플릿에서 단일 따옴표를 이스케이프하는 방법 (0) | 2023.06.07 |
Firebase의 다중 where 절을 기준으로 쿼리 (0) | 2023.06.07 |
여러 CSV 파일을 단일 xls 워크북 Python 3에 결합 (0) | 2023.06.07 |
길이가 큰 VARCHAR2 열 정의의 영향 (0) | 2023.06.07 |