代码之家  ›  专栏  ›  技术社区  ›  Konstantin

确定红宝石中嵌套数组的中位数元素?

  •  -2
  • Konstantin  · 技术社区  · 6 年前

    我需要Ruby中的一个中值计算方法,它同样适用于嵌套数组,类似于“UNIQ”和“SotJyby”:我可以通过块定义这些嵌套数组值中的哪一个。

    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 回复  |  直到 6 年前
        1
  •  2
  •   Simple Lime    6 年前

    既然中位数需要排序,你可以委托给 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个不同的数组看起来像什么。这采用了简单的(对我们来说)方法,返回中心元素,调用方必须决定如何处理它们。(如果它不是嵌套在内部的另一个数组,如果它是一个列表,例如,你想用姓氏的中间值,那该怎么办?)

        2
  •  0
  •   Cary Swoveland    6 年前

    我假设数组的中值定义如下。对于数组 a 包含奇数个元素,中位数为 [m] 哪里 m 为此 e <=> m 对于 a.size/2 其他要素 e E<=>米 其余部分为非负 A.尺寸/2 其他要素 E类 是的。对于具有偶数个元素的数组,中位数是 [m, n] ,其中 n 为此 m <=> n 是非阳性的, E<=>米 对于 a.size/2-1 其他要素 E类 e <=> n 其余部分为非负 A.尺寸/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中引入的。

        3
  •  -1
  •   David Hempy    6 年前

    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能为你优化。但老实说,我不会担心表演。

    编辑后,KydoRess指出我混淆了中值和中值!谢谢,孩子!]