开发者

First order array difference in Ruby

What's the slickest, most Ruby-like way to do this?

[1, 3, 10, 5].diff

should produce

[2, 7, -5]

that is, an array of first order differences. I've come up with a solution which I'll add below, but it requires ruby 1开发者_如何转开发.9 and isn't all that slick. what else is possible?


I like this functional style:

module Enumerable
  def diff
    each_cons(2).map {|pair| pair.reverse.reduce :-}
  end
end

EDIT: I just realized that the reverse is totally unnecessary. If this were a functional language, I would have used pattern matching, but Ruby doesn't support pattern matching. It does, however, support destructuring bind, which is a good enough approximation for pattern matching in this case.

each_cons(2).map {|first, second| second - first}

No smiley, though.

I like how this sounds if you just read it out loud from left to right: "For each pair, apply the difference between the first and second elements of the pair." In fact, I normally don't like the name collect and prefer map instead, but in this case that reads even better:

each_cons(2).collect {|first, second| second - first}

"For each pair, collect the difference between its elements." Sounds almost like a definition of first order difference.


Yet another way..Seems the shortest so far:)

  module Enumerable
    def diff
        self[1..-1].zip(self).map {|x| x[0]-x[1]}
    end    
  end


The concept comes from functional programming, of course:

module Enumerable
  def diff
    self.inject([0]) { |r,x| r[-1] += x; r << -x } [1..-2]
  end
end

[1,3,10,5].diff

Note that you don't need any separate intermediate variables here


Here's the fastest way I could find (faster than all the others suggested here as of this moment, in both 1.8 and 1.9):

module Enumerable
  def diff
    last=nil
    map do |x|
      r = last ? x - last : nil
      last = x
      r
    end.compact
  end
end

With this close runner-up:

module Enumerable
  def diff
    r = []
    1.upto(size-1) {|i| r << self[i]-self[i-1]}
    r
  end
end

Of the others here, testr's self-described "feeble" attempt is the next fastest, but it's still slower than either of these.

And if speed is no object, here's my aesthetic favorite:

module Enumerable
  def diff!
    [-shift+first] + diff! rescue []
  end

  def diff
    dup.diff!
  end
end

But this is (for reasons I don't entirely understand) an order of magnitude slower than any other suggestion here!


Minor variation on Jörg W Mittag's:

module Enumerable
  def diff
    each_cons(2).map{|a,b| b-a}
  end
end


# Attempt, requires ruby 1.9.
module Enumerable
  def diff
    each_cons(2).with_object([]){|x,array| array << x[1] - x[0]}
  end
end

Example:

[1,3,10,5].diff
=> [2, 7, -5]


Another way to do it.

module Enumerable
  def diff
    result = []
    each_with_index{ |x, i|
      return result if (i == (self.length-1))
      result << self[i+1] - x
    }
  end
end


My feeble attempt...

module Enumerable
  def diff
    na = []
    self.each_index { |x| r << self[x]-self[x-1] if x > 0 }
    na
  end
end

p [1,3,10,5].diff  #returned [2, 7, -5]
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜