在 Ruby 中计算中位数
Posted
技术标签:
【中文标题】在 Ruby 中计算中位数【英文标题】:Calculating Median in Ruby 【发布时间】:2013-01-29 07:52:00 【问题描述】:如何使用 Ruby 计算数字数组的中位数?
我是一个初学者,正在努力处理数组长度为奇数和偶数的情况。
【问题讨论】:
您可能想要使用 Gem,例如github.com/ankane/active_median 【参考方案1】:我喜欢使用 Refinements,这是一种Monkey Patch ruby 类的安全方法,不会对系统产生附带影响。
用法变得比新方法更简洁。
使用Refinements,您可以修改Array
类,实现Array#median
,此方法仅在使用细化的类范围内可用! :)
改进
module ArrayRefinements
refine Array do
def median
return nil if empty?
sorted = sort
(sorted[(length - 1) / 2] + sorted[length / 2]) / 2.0
end
end
end
class MyClass
using ArrayRefinements
# You can use the Array#median as you wish here
def test(array)
array.median
end
end
MyClass.new.test([1, 2, 2, 2, 3])
=> 2.0
【讨论】:
【参考方案2】:这是一个适用于偶数和奇数长度数组且不会改变数组的解决方案:
def median(array)
return nil if array.empty?
sorted = array.sort
len = sorted.length
(sorted[(len - 1) / 2] + sorted[len / 2]) / 2.0
end
【讨论】:
return 0 if array.empty?
@ArtemKalinchuk 为什么是 0?空数组的中位数未定义。我同意应该改进此方法以通过返回 Float::NAN
之类的内容或引发自定义的更明确的错误来处理这种情况。【参考方案3】:
def median(array, already_sorted=false)
return nil if array.empty?
array = array.sort unless already_sorted
m_pos = array.size / 2
return array.size % 2 == 1 ? array[m_pos] : mean(array[m_pos-1..m_pos])
end
【讨论】:
【参考方案4】:这里有一个解决方案:
app_arry = [2, 3, 4, 2, 5, 6, 16].sort
# check array isn't empty
if app_arry.empty? || app_arry == ""
puts "Sorry, This will not work."
return nil
end
length = app_arry.length
puts "Array length = #length"
puts "Array = #app_arry"
if length % 2 == 0
# even number of elements
puts "median is #(app_arry[length/2].to_f + app_arry[(length-1)/2].to_f)/2"
else
# odd number of elements
puts "median is #app_arry[(length-1)/2]"
end
输出
数组长度 = 7
数组 = [2, 3, 4, 2, 5, 6, 16]
中位数是 2
【讨论】:
【参考方案5】:def median(arr)
sorted = arr.sort
if sorted == []
return nil
end
if sorted.length % 2 != 0
result = sorted.length / 2 # 7/2 = 3.5 (rounded to 3)
return sorted[result] # 6
end
if sorted.length % 2 == 0
result = (sorted.length / 2) - 1
return (sorted[result] + sorted[result+1]) / 2.0 # (4 + 5) / 2
end
end
p median([5, 0, 2, 6, 11, 10, 9])
【讨论】:
【参考方案6】: def median(array) #Define your method accepting an array as an argument.
array = array.sort #sort the array from least to greatest
if array.length.odd? #is the length of the array odd?
array[(array.length - 1) / 2] #find value at this index
else array.length.even? #is the length of the array even?
(array[array.length/2] + array[array.length/2 - 1])/2.to_f
#average the values found at these two indexes and convert to float
end
end
【讨论】:
有很多方法可以做到这一点,但你的答案是最优雅的。很清楚发生了什么。 如果array.length不是奇数,那么是偶数,还是别的什么?,else后面的表达式是不是必须的,return也需要吗? 我认为也不需要均匀评估。【参考方案7】:处理边缘情况的更正确解决方案:
class Array
def median
sorted = self.sort
size = sorted.size
center = size / 2
if size == 0
nil
elsif size.even?
(sorted[center - 1] + sorted[center]) / 2.0
else
sorted[center]
end
end
end
有一个规格要证明:
describe Array do
describe '#median' do
subject arr.median
context 'on empty array' do
let(:arr) []
it is_expected.to eq nil
end
context 'on 1-element array' do
let(:arr) [5]
it is_expected.to eq 5
end
context 'on 2-elements array' do
let(:arr) [1, 2]
it is_expected.to eq 1.5
end
context 'on odd-size array' do
let(:arr) [100, 5, 2, 12, 1]
it is_expected.to eq 5
end
context 'on even-size array' do
let(:arr) [7, 100, 5, 2, 12, 1]
it is_expected.to eq 6
end
end
end
【讨论】:
【参考方案8】:def median(array)
half = array.sort!.length / 2
array.length.odd? ? array[half] : (array[half] + array[half - 1]) / 2
end
*如果长度是偶数,则必须加上中间点加上中间点-1来说明从0开始的索引
【讨论】:
使用array.sort!
不是一个好主意,因为它会改变参数【参考方案9】:
类似于 nbarraille,但我发现跟踪它的工作原理更容易一些:
class Array
def median
sorted = self.sort
half_len = (sorted.length / 2.0).ceil
(sorted[half_len-1] + sorted[-half_len]) / 2.0
end
end
half_len = 直到并包括(对于奇数项的数组)数组中间的元素数。
更简单:
class Array
def median
sorted = self.sort
mid = (sorted.length - 1) / 2.0
(sorted[mid.floor] + sorted[mid.ceil]) / 2.0
end
end
【讨论】:
【参考方案10】:我觉得不错:
#!/usr/bin/env ruby
#in-the-middle value when odd or
#first of second half when even.
def median(ary)
middle = ary.size/2
sorted = ary.sort_by |a| a
sorted[middle]
end
或
#in-the-middle value when odd or
#average of 2 middle when even.
def median(ary)
middle = ary.size/2
sorted = ary.sort_by |a| a
ary.size.odd? ? sorted[middle] : (sorted[middle]+sorted[middle-1])/2.0
end
我使用 sort_by 而不是 sort,因为它更快:Sorting an array in descending order in Ruby。
【讨论】:
【参考方案11】:如果计算中位数是指this
然后
a = [12,3,4,5,123,4,5,6,66]
a.sort!
elements = a.count
center = elements/2
elements.even? ? (a[center] + a[center+1])/2 : a[center]
【讨论】:
是的,第一个偶数使它成为一个 if ... else 过程(到目前为止我所学到的) 不一定要有if/else,看我的回答 需要2.0
或to_f
才能使4.5 之类的结果成为可能。
另外最后一行应该是elements.even? ? (a[center] + a[center-1])/2.0 : a[center]
(注意a[center-1]
和2.0
中的减号)否则偶数长度数组的中值会偏移数组中的1个索引位置.尝试使用 2 值数组的原始代码,你会得到一个错误。这只是咬我...以上是关于在 Ruby 中计算中位数的主要内容,如果未能解决你的问题,请参考以下文章