Forum: Ruby Creating an array of differences

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Ab6662d4241124bf3f2971197915e309?d=identicon&s=25 Jason Madigan (nuphor)
on 2007-04-09 15:46
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.
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-04-09 16:17
(Received via mailing list)
On Apr 9, 2007, at 8:46 AM, Jason Madigan 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 Gray II
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2007-04-09 16:20
(Received via mailing list)
On 09.04.2007 15:46, Jason Madigan 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
8f6f95c4bd64d5f10dfddfdcd03c19d6?d=identicon&s=25 Rick Denatale (rdenatale)
on 2007-04-09 16:40
(Received via mailing list)
On 4/9/07, Jason Madigan <nuphor@gmail.com> 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/
Ab6662d4241124bf3f2971197915e309?d=identicon&s=25 Jason Madigan (nuphor)
on 2007-04-09 16:48
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 :)
376b37712da46bc511eac502afe86422?d=identicon&s=25 Reuben Grinberg (Guest)
on 2007-04-09 19:01
(Received via mailing list)
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
This topic is locked and can not be replied to.