Creating an array of differences


#1

Hey there,

I’m pretty new to Ruby so perhaps some of you could help me out with a
little problem I’ve come up against. I have an array consisting of
integers (called session[:octets_in]). What I want to do is create an
array comprising of the difference between the current element and the
previous element (e.g. [“1000”, “1100”, “1200”] would become [“100”,
“200”]). I’m not entirely sure how to go about this, so any pointers
would be welcome.


#2

On Apr 9, 2007, at 8:46 AM, Jason M. wrote:

Hey there,

Hello.

I’m pretty new to Ruby so perhaps some of you could help me out with a
little problem I’ve come up against.

Sure. Welcome to Ruby.

I have an array consisting of
integers (called session[:octets_in]). What I want to do is create an
array comprising of the difference between the current element and the
previous element (e.g. [“1000”, “1100”, “1200”] would become [“100”,
“200”]).

Hmm, your description and your example don’t say the same thing.
I’ll assume you meant the answer should be [“100”, “100”].

I’m not entirely sure how to go about this, so any pointers
would be welcome.

With just core Ruby you could do:

data = %w[1000 1100 1200]
=> [“1000”, “1100”, “1200”]

(1…(data.size - 1)).inject(Array.new) do |diffs, i|
?> diffs + [(data[i - 1].to_i - data[i].to_i).abs.to_s]

end
=> [“100”, “100”]

However, I think it looks a little prettier if you load a standard
library and solve it like this:

require “enumerator”
=> true

data.enum_cons(2).map { |l, r| (l.to_i - r.to_i).abs.to_s }
=> [“100”, “100”]

Hope that helps.

James Edward G. II


#3

On 09.04.2007 15:46, Jason M. wrote:

I’m pretty new to Ruby so perhaps some of you could help me out with a
little problem I’ve come up against. I have an array consisting of
integers (called session[:octets_in]). What I want to do is create an
array comprising of the difference between the current element and the
previous element (e.g. [“1000”, “1100”, “1200”] would become [“100”,
“200”]). I’m not entirely sure how to go about this, so any pointers
would be welcome.

I think you would get [100,100] in your case (apart from the fact that
the array you present is an array of strings).

I think the most elegant solution is with #each_cons; with enumerator
you can do:

irb(main):007:0> (1…10).to_enum(:each_cons, 2).map {|a,b| b-a}
=> [1, 1, 1, 1, 1, 1, 1, 1, 1]

irb(main):008:0> [1000,1100,1200].to_enum(:each_cons, 2).map {|a,b| b-a}
=> [100, 100]

Kind regards

robert


#4

All,

Thank you very much for all your replies, they’re incredibly helpful!
And apologies for my mistake in the original post, I of course meant
[“100”, “100”]. You’ve all given me plenty of food for thought :slight_smile:


#5

On 4/9/07, Jason M. removed_email_address@domain.invalid wrote:

Hey there,

I’m pretty new to Ruby so perhaps some of you could help me out with a
little problem I’ve come up against. I have an array consisting of
integers (called session[:octets_in]). What I want to do is create an
array comprising of the difference between the current element and the
previous element (e.g. [“1000”, “1100”, “1200”] would become [“100”,
“200”]). I’m not entirely sure how to go about this, so any pointers
would be welcome.

Did you really mean that this would produce [“100”, “100”]? since the
element before “1200” is “1100” not “1000”.

require ‘enumerator’

[“1000”, “1100”, “1200”, “1420”].enum_for(:each_cons, 2).map {|a, b|
(b.to_i - a.to_i).to_s} => [“100”, “100”, “220”]

If you really meant the difference between the second and subsequent
elements and the first, then here’s a tricksy way to to it:

[“1000”, “1100”, “1200”].inject(nil) {|s,e| s ? s << (e.to_i -
s.first.to_i).to_s : [e]}[1…-1]

It stores the first element in the ‘sum’ being computed by inject,
then strips it off.

Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/


#6

Here’s another way of doing it:

(a.zip(a[1…a.length])[0…a.length-1]).map { |a,b| b-a }

This things makes an array of pairs of the elements:

irb(main):007:0> a = [1000, 1100, 1200]
=> [1000, 1100, 1200]
irb(main):029:0> a.zip(a[1…a.length])[0…a.length-1]
=> [[1000, 1100], [1100, 1200]]
irb(main):030:0> (a.zip(a[1…a.length])[0…a.length-1]).map { |a,b| b-a
}
=> [100, 100]

-Reuben