确定 Ruby 中嵌套数组的中值元素?
Determine median element of a nested array in Ruby?
我需要 Ruby 中的中位数计算方法,它也适用于嵌套数组,类似于 "uniq" 和 "sort_by":对于我可以通过块定义的那些,应考虑嵌套数组值的数量。
class Array
def median
. . .
end
end
puts [[1,3],[2,5],[3,-4]].median{|z,w| z}
=> [2,5]
puts [[1,3],[2,5],[3,-4]].median{|z,w| w}
=> [1,3]
我确定我应该以某种方式处理 "yield",但我不知道该怎么做。
flatten() 是你的朋友。它将嵌套数组(或任何可枚举数组)折叠成单个数组。然后,计算中位数变得微不足道:
class Array
def median
array = self.flatten.sort
if array.size % 2 == 1
array[array.size / 2]
else
mid = array.size / 2
(array[mid] + array[mid-1]) / 2.0
end
end
def mean
self.flatten.reduce(:+) / self.flatten.size.to_f
end
end
这让您可以:
irb> a
=> [[1, 3], [2, 5], [3, -4]]
irb> a.median
=> 2.5
irb> c
=> [[1, 2, 3, 6], [4, 5, [100]]]
irb> c.median
=> 4
irb> c.mean
=> 17.285714285714285
为了提高性能,您可能需要计算 self.flatten 一次,然后对该数组执行两个算术运算。但是,除非您使用大量数据,否则这可能无关紧要,希望 Ruby 会为您优化它。但老实说,我不会担心性能。
[已编辑,@kiddorails 指出我混淆了中位数和均值!谢谢,孩子!]
由于中位数需要排序,您可以委派给 sort_by
并处理结果:
class Array
def median(&block)
block = :itself unless block_given?
sorted = sort_by(&block)
if length.odd?
sorted[sorted.length / 2]
else
sorted[sorted.length / 2 - 1, 2]
end
end
end
样本运行:
[13, 23, 11, 16, 15, 10, 26].median # => 15
# hyperbole showing the block is used on single elements
count = 0; [13, 23, 11, 16, 15, 10, 26].median { |a| count += 1 } # => 16
# even length data set
# usually you'd average these, but that becomes trickier with nested arrays
[14, 13, 23, 11, 16, 15, 10, 26].median # => [14, 15]
# your examples:
[[1,3], [2,5], [3,-4]].median { |z,_| z} # => [2, 5]
[[1,3], [2,5], [3,-4]].median { |_,w| w } # => [1, 3]
# added [6, -6] to your examples:
[[1,3], [2,5], [3,-4], [6, -6]].median { |z,_| z } # => [[2, 5], [3, -4]]
[[1,3], [2,5], [3,-4], [6, -6]].median { |_,w| w } # => [[3, -4], [1, 3]]
您没有指定偶数长度数组应该发生什么。对于数学中位数(如果我没记错的话)你会平均两个最中心的元素,但随之而来的问题是 2 个不同数组的平均值是什么样的。这采用了返回中心元素的简单(对我们而言)方法,调用者必须决定如何处理它们。 (如果它不是嵌套在里面的另一个数组,如果它是一个人的列表,并且你想要姓氏的中位数怎么办,例如)
我假设数组的中位数定义如下。对于包含奇数个元素的数组 a
,中位数是 [m]
,其中 m
是 a
的一个元素,其中 e <=> m
是非正数a.size/2
其他元素 e
和 e <=> m
对于剩余的 a.size/2
其他元素 e
是非负的。对于具有偶数个元素的数组,中位数为 [m, n]
,其中 m
和 n
是 a
的元素,其中 m <=> n
为非正数, e <=> m
对于 a.size/2-1
个其他元素是非正数 e
并且 e <=> n
对于剩余的 a.size/2-1
个其他元素是非负数 e
.
class Array
def median
min_by(1+self.size/2, &:itself).pop(self.size.odd? ? 1 : 2)
end
end
[2, 4, 5, 3, 1].median
#=> [3]
[2, 6, 4, 5, 3, 1].median
#=> [3, 4]
[3, 6, 4, 5, 3, 1].median
#=> [3, 4]
['hamster', 'dog', 'fish', 'cat'].median
#=> ["dog", "fish"]
[[1, 3], [2, 5], [3, -4]].median
#=> [[2, 5]]
[[2,6], [3,-4], [1,3], [2,5]].median
# => [[2, 5], [2, 6]]
arr = [[[3,1], 1], [[4], 2], [[2,1], 4, 1], [[3,1], 0], [[1,2,3], 5]]
arr.median
#=> [[[3, 1], 0]]
最后一个例子
arr.sort
#=> [[[1, 2, 3], 5], [[2, 1], 4, 1], [[3, 1], 0], [[3, 1], 1], [[4], 2]]
参见 Enumerable#min_by。可选参数在 Ruby v2.1.
中引入
我需要 Ruby 中的中位数计算方法,它也适用于嵌套数组,类似于 "uniq" 和 "sort_by":对于我可以通过块定义的那些,应考虑嵌套数组值的数量。
class Array
def median
. . .
end
end
puts [[1,3],[2,5],[3,-4]].median{|z,w| z}
=> [2,5]
puts [[1,3],[2,5],[3,-4]].median{|z,w| w}
=> [1,3]
我确定我应该以某种方式处理 "yield",但我不知道该怎么做。
flatten() 是你的朋友。它将嵌套数组(或任何可枚举数组)折叠成单个数组。然后,计算中位数变得微不足道:
class Array
def median
array = self.flatten.sort
if array.size % 2 == 1
array[array.size / 2]
else
mid = array.size / 2
(array[mid] + array[mid-1]) / 2.0
end
end
def mean
self.flatten.reduce(:+) / self.flatten.size.to_f
end
end
这让您可以:
irb> a
=> [[1, 3], [2, 5], [3, -4]]
irb> a.median
=> 2.5
irb> c
=> [[1, 2, 3, 6], [4, 5, [100]]]
irb> c.median
=> 4
irb> c.mean
=> 17.285714285714285
为了提高性能,您可能需要计算 self.flatten 一次,然后对该数组执行两个算术运算。但是,除非您使用大量数据,否则这可能无关紧要,希望 Ruby 会为您优化它。但老实说,我不会担心性能。
[已编辑,@kiddorails 指出我混淆了中位数和均值!谢谢,孩子!]
由于中位数需要排序,您可以委派给 sort_by
并处理结果:
class Array
def median(&block)
block = :itself unless block_given?
sorted = sort_by(&block)
if length.odd?
sorted[sorted.length / 2]
else
sorted[sorted.length / 2 - 1, 2]
end
end
end
样本运行:
[13, 23, 11, 16, 15, 10, 26].median # => 15
# hyperbole showing the block is used on single elements
count = 0; [13, 23, 11, 16, 15, 10, 26].median { |a| count += 1 } # => 16
# even length data set
# usually you'd average these, but that becomes trickier with nested arrays
[14, 13, 23, 11, 16, 15, 10, 26].median # => [14, 15]
# your examples:
[[1,3], [2,5], [3,-4]].median { |z,_| z} # => [2, 5]
[[1,3], [2,5], [3,-4]].median { |_,w| w } # => [1, 3]
# added [6, -6] to your examples:
[[1,3], [2,5], [3,-4], [6, -6]].median { |z,_| z } # => [[2, 5], [3, -4]]
[[1,3], [2,5], [3,-4], [6, -6]].median { |_,w| w } # => [[3, -4], [1, 3]]
您没有指定偶数长度数组应该发生什么。对于数学中位数(如果我没记错的话)你会平均两个最中心的元素,但随之而来的问题是 2 个不同数组的平均值是什么样的。这采用了返回中心元素的简单(对我们而言)方法,调用者必须决定如何处理它们。 (如果它不是嵌套在里面的另一个数组,如果它是一个人的列表,并且你想要姓氏的中位数怎么办,例如)
我假设数组的中位数定义如下。对于包含奇数个元素的数组 a
,中位数是 [m]
,其中 m
是 a
的一个元素,其中 e <=> m
是非正数a.size/2
其他元素 e
和 e <=> m
对于剩余的 a.size/2
其他元素 e
是非负的。对于具有偶数个元素的数组,中位数为 [m, n]
,其中 m
和 n
是 a
的元素,其中 m <=> n
为非正数, e <=> m
对于 a.size/2-1
个其他元素是非正数 e
并且 e <=> n
对于剩余的 a.size/2-1
个其他元素是非负数 e
.
class Array
def median
min_by(1+self.size/2, &:itself).pop(self.size.odd? ? 1 : 2)
end
end
[2, 4, 5, 3, 1].median
#=> [3]
[2, 6, 4, 5, 3, 1].median
#=> [3, 4]
[3, 6, 4, 5, 3, 1].median
#=> [3, 4]
['hamster', 'dog', 'fish', 'cat'].median
#=> ["dog", "fish"]
[[1, 3], [2, 5], [3, -4]].median
#=> [[2, 5]]
[[2,6], [3,-4], [1,3], [2,5]].median
# => [[2, 5], [2, 6]]
arr = [[[3,1], 1], [[4], 2], [[2,1], 4, 1], [[3,1], 0], [[1,2,3], 5]]
arr.median
#=> [[[3, 1], 0]]
最后一个例子
arr.sort
#=> [[[1, 2, 3], 5], [[2, 1], 4, 1], [[3, 1], 0], [[3, 1], 1], [[4], 2]]
参见 Enumerable#min_by。可选参数在 Ruby v2.1.
中引入