배열에서 평균을 어떻게 구할 수 있습니까?
배열이있는 경우 :
[0,4,8,2,5,0,2,6]
평균화하면 3.375가 표시됩니다.
배열에서 평균을 어떻게 구할 수 있습니까?
배열이있는 경우 :
[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
훌륭하지만 어떤 일이 일어나고 있는지 모른다면 약간 영리합니다. 는 :+
심볼이고; 주입하도록 전달되면 누적 기 값에 대해 기호로 명명 된 메소드 (이 경우 추가 연산)가 각 요소에 적용됩니다.
arr.inject(0.0) { |sum,el| sum + el } / arr.size
.
inject
. 설명서에서 언급 한 인터페이스 의 일부입니다 . to_proc
연산자이다 &
.
Array#inject
여기서 과잉입니다. 그냥 사용하십시오 #sum
. 예arr.sum.to_f / arr.size
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
instance_eval
a
한 번만 지정하면서 코드를 실행할 수 있으므로 다른 명령과 연결될 수 있습니다. 즉 random_average = Array.new(10) { rand(10) }.instance_eval { reduce(:+) / size.to_f }
대신random = Array.new(10) { rand(10) }; random_average = random.reduce(:+) / random.size
self
해당 블록 내부의 변수 또는 메소드에 액세스하고 인스턴스를 시도하면 문제가 발생할 수 있습니다.) instance_eval
메타 프로그래밍 또는 DSL에 더 적합합니다.
가장 간단한 대답은
list.reduce(:+).to_f / list.size
reduce
의 방법입니다 . 당신은 어느 구현 레일을 사용하지 않는 그리고 그 이름에도 불구하고, I합니다 ... @ShuWu에 동의 . Enumerable
Array
sum
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
nil
이 0 이 아닌 왜 됩니까?
제로 문제로 나눗셈을 해결하는 무언가를 경쟁으로 가져 갑시다.
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
빈 배열에 대한 결과는 예상대로 예외가 아니지만 대신 NaN을 반환합니다 ... 루비에서는 전에 본 적이 없습니다. ;-) Float 클래스의 특별한 동작 인 것 같습니다 ...
0.0/0 #==> NaN
0.1/0 #==> Infinity
0.0.class #==> Float
수용된 솔루션에 대해 내가 싫어하는 것
arr = [5, 6, 7, 8]
arr.inject{ |sum, el| sum + el }.to_f / arr.size
=> 6.5
실제로 순전히 기능적인 방식으로 작동하지 않는다는 것입니다. 끝에 arr.size를 계산하려면 변수 arr이 필요합니다.
이 기능을 순전히 기능적으로 해결하려면 모든 요소의 합과 요소 수의 두 가지 값을 추적해야합니다.
[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(:/)
end.method
루비에서 처음 사용 된 것을 보았습니다 . 감사합니다!
arr.inject([0.0,0]) { |(sum, size), el| [ sum + el, size + 1 ] }.inject(:/)
공공 오락을위한 또 다른 해결책 :
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
Array#average
.나는 똑같은 일을 자주하고 있었기 때문에 Array
간단한 average
방법으로 수업을 확장하는 것이 현명하다고 생각했습니다 . 정수 또는 부동 소수점 또는 소수와 같은 숫자 배열 이외의 다른 경우에는 작동하지 않지만 올바르게 사용하면 편리합니다.
Ruby on Rails를 사용하고 있기 때문에 이것을 배치 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 / self.size
end
end
a = [0,4,8,2,5,0,2,6]
sum = 0
a.each { |b| sum += b }
average = sum / a.length
이 방법이 도움이 될 수 있습니다.
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])
[1,2].tap { |a| @asize = a.size }.inject(:+).to_f/@asize
짧지 만 인스턴스 변수 사용
a_size = nil; [1,2].tap { |a| a_size = a.size }.inject(:+).to_f/a_size
인스턴스 변수를 만드는 것이 아니라 할 것입니다.