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

Ruby中的累积数组和

  •  24
  • Peter  · 技术社区  · 16 年前

    计算数组累积和的最巧妙、最像红宝石的方法是什么?

    例子:

    [1,2,3,4].cumulative_sum
    

    应该返回

    [1,3,6,10]
    
    8 回复  |  直到 8 年前
        1
  •  35
  •   khelll    16 年前
    class Array
      def cumulative_sum
        sum = 0
        self.map{|x| sum += x}
      end
    end
    
        2
  •  10
  •   hrnt    16 年前

    这是一条路

    a = [1, 2, 3, 4]
    a.inject([]) { |x, y| x + [(x.last || 0) + y] }
    

    如果答案是多个陈述可以,那么这将更清楚:

    outp = a.inject([0]) { |x, y| x + [x.last + y] }
    outp.shift # To remove the first 0
    
        3
  •  7
  •   rampion    16 年前
     irb> a = (1..10).to_a
     #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
     irb> a.inject([0]) { |(p,*ps),v| [v+p,p,*ps] }.reverse[1..-1]
     #=> [1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
    

    我们也可以从haskell那里记下,然后制作一个Ruby版本的 scanr .

    irb> class Array
       >   def scanr(init)
       >     self.inject([init]) { |ps,v| ps.unshift(yield(ps.first,v)) }.reverse
       >   end
       > end
    #=> nil
    irb> a.scanr(0) { |p,v| p + v }
    => [0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
    irb> a.scanr(0) { |p,v| p + v }[1..-1]
    => [1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
    irb> a.scanr(1) { |p,v| p * v }
    => [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]
    
        4
  •  2
  •   Nakilon earlonrails    10 年前

    你也可以阅读 scanl “你需要的”特性,但据我所知,它还没有在Ruby中实现。下面是它的示例和示例源代码: http://billsix.blogspot.com/2008/11/functional-collection-patterns-in-ruby.html

    更新: 上面的链接已经死了,所以我要说的是我的wolfram mathematica的ruby实现 FoldList[] 作为GEM“MLL”的一部分 here 在可枚举的情况下,可以简化OP的用途:

    def fold_list array
      start = 0
      Enumerator.new do |e|
        array.each do |i|
          e << start += i
        end
      end
    end
    
    irb> fold_list([1,2,3]).to_a
    => [1, 3, 6]
    
        5
  •  1
  •   Harish Shetty    16 年前

    还有一种方法(尽管我更喜欢 凯尔 s)

    (1..10).inject([]) { |cs, i| cs << i + (cs.last || 0) }
    

    我看到答案贴在 心率变异性指数 在发布我的答案之后。虽然两种方法看起来是相同的,但是上面的解决方案比在每个注入循环中使用相同的数组更有效。

    a,r = [1, 2, 3, 4],[]
    k = a.inject(r) { |x, y| x + [(x.last || 0) + y] }
    p r.object_id 
    #  35742260
    p k.object_id
    #  35730450
    

    你会发现r和k是不同的。如果对上述溶液进行相同的测试:

    a,r = [1, 2, 3, 4],[]
    k = a.inject(r) { |cs, i| cs << i + (cs.last || 0) }
    p r.object_id
    # 35717730
    p k.object_id
    # 35717730
    

    r和k的对象ID相同。

        6
  •  1
  •   m_x    14 年前

    为了另一个方法挖掘这个,那个 就地修改数组

    class Array
      def cumulative_sum!
        (1..size-1).each {|i| self[i] += self[i-1] }
        self
      end
    end
    

    也可以概括为:

      def cumulate!( &block )
        (1..size-1).each {|i| self[i] = yield self[i-1], self[i] }
        self
      end
    
      >> (1..10).to_a.cumulate! {|previous, next| previous * next }
      => [1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]
    
        7
  •  1
  •   Rahul Patel    8 年前

    试试这个代码

    [1,2,3,4].inject([]){ |acc, value| acc << acc.last.to_i + value.to_i }
    
    => [1, 3, 6, 10]
    
        8
  •  0
  •   FelipeC    8 年前

    我们需要的haskell函数是 scanl 不是 scanr .

    class Array
      def scanl(init)
        self.reduce([init]) { |a, e| a.push(yield(a.last, e)) }
      end
    end
    
    [1,2,3,4].scanl(0) { |a, b| a + b }[1..-1]
    => [1, 3, 6, 10]
    
    推荐文章