确定Ruby中嵌套数组的中值元素?

时间:2018-06-24 04:31:09

标签: arrays ruby multidimensional-array yield median

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

我确定我应该以某种方式处理“收益”,但是我不知道该怎么做。

3 个答案:

答案 0 :(得分:2)

由于中位数需要排序,因此您可以将其委托给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个不同数组的平均值是什么样的问题。这采用返回中心元素和调用者必须决定如何处理它们的简单(对我们而言)方法。 (例如,如果它不是嵌套的另一个数组,或者如果它是一个人的列表,并且您想要按姓氏表示的中位数,该怎么办?)

答案 1 :(得分:0)

我假设数组的中位数定义如下。对于包含奇数个元素的数组a,中位数为[m],其中ma的元素,其中e <=> m的正值为负。 a.size/2个其他元素ee <=> m对于其余a.size/2个其他元素e是非负的。对于元素数为偶数的数组,中位数为[m, n],其中mna的元素,其中m <=> n为非正数, e <=> ma.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中引入的。

答案 2 :(得分:-1)

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指出我混淆了中位数和均值之后!谢谢,Kiddo!]