Difference first order arrays in Ruby

What is the smoothest, 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 came up with a solution that I will add below, but it requires a ruby ​​of 1.9 and not all that stain. what else is possible?

+6
ruby
source share
8 answers

Another way ... It seems to be the shortest :)

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

I like this functional style:

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

EDIT: I just realized that reverse completely unnecessary. If it were a functional language, I would use pattern matching, but Ruby does not support pattern matching. However, it does support destructive binding, which is a good enough approximation for pattern matching in this case.

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

No emoticons.

I like how it sounds if you just read it loudly from left to right: "For each pair, apply the difference between the first and second elements of the pair." Actually, I usually don't like the name collect and prefer map instead, but in this case it looks even better:

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

"For each pair, collect the difference between its elements." It almost sounds like a first-order difference.

+5
source share

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 

Please note that here you do not need any separate intermediate variables

+2
source share

Here is the fastest way I could find (faster than all the others offered here from now on, both in 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 next lesson:

 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 "weak" attempt is the next fastest, but it is still slower than any of these.

And if speed is not an object, here is my esthetic favorite:

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

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

+2
source share

Minor change to Jörg W Mittag's:

 module Enumerable def diff each_cons(2).map{|a,b| ba} end end 
+2
source share
 # 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] 
+1
source share

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 
0
source share

My weak 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
source share

All Articles