Best style for setting items in a collection

I've only recently started learning Ruby and notice in Thomas'
Programming Ruby 1.9 that it seems to be stylistically preferable (and
presumably also faster fwiw) not to use a for loop but rather to use the
each method as often as possible. But I'm having trouble using combining
that with re-assigning values inside an array.

More specifically, consider the following problem: We have an array of
integers and want the result to be the same as the following for loop:

for i in 1...arr.length
   arr[i] += arr[i - 1]
end

Is it stylistically better to use the for loop here or do something like
this:

1.upto(arr.length - 1) {|i| arr[i] += arr[i - 1]}

Or is there another way of doing it that is better than both of these? I
feel like I should be able to do this using the each method but can't
figure out how to make the assignment work that way, and the upto
version is pretty short and sweet.

···

--
Posted via http://www.ruby-forum.com/.

feel like I should be able to do this using the each method but can't
figure out how to make the assignment work that way, and the upto
version is pretty short and sweet.

Does this #each give you what you want?
This is your way but with #each.

(1...arr.length).each{|i| arr[i] += arr[i - 1]}

Harry

I'm not sure what you're calculating here, but if I wanted to add the items in an Array with one item to the left I would use:

arr.zip(arr.rotate).map { |a, b| a + b }

This doesn't calculate the same result as yours, but I'm not sure exactly what you want to do.

···

On Jul 23, 2011, at 6:41 PM, Marshall Farrier wrote:

I've only recently started learning Ruby and notice in Thomas'
Programming Ruby 1.9 that it seems to be stylistically preferable (and
presumably also faster fwiw) not to use a for loop but rather to use the
each method as often as possible. But I'm having trouble using combining
that with re-assigning values inside an array.

More specifically, consider the following problem: We have an array of
integers and want the result to be the same as the following for loop:

for i in 1...arr.length
  arr[i] += arr[i - 1]
end

Is it stylistically better to use the for loop here or do something like
this:

1.upto(arr.length - 1) {|i| arr[i] += arr[i - 1]}

Or is there another way of doing it that is better than both of these? I
feel like I should be able to do this using the each method but can't
figure out how to make the assignment work that way, and the upto
version is pretty short and sweet.

It's hard to know how to answer this because you're overwriting the values
of indexes that you use in calculations later on. This seems like it is
probably unintentional: If arr was [1,1,1], then are you expecting [1,2,2]
-- the value at index 2 is calculated based on the original value at index
1. Or are you expecting [1,2,3] -- the value at index 2 is calculated based
on the new value at index 1?

If the former, then this is equivalent:
arr.each_cons(2).with_index(1) do |(left, right), index|
  arr[index] = left + right
end

If the latter, then this is equivalent:
(1...arr.length).each { |index| arr[index] += arr[index-1] }

···

On Sat, Jul 23, 2011 at 8:41 PM, Marshall Farrier <info@marshallfarrier.com>wrote:

I've only recently started learning Ruby and notice in Thomas'
Programming Ruby 1.9 that it seems to be stylistically preferable (and
presumably also faster fwiw) not to use a for loop but rather to use the
each method as often as possible. But I'm having trouble using combining
that with re-assigning values inside an array.

More specifically, consider the following problem: We have an array of
integers and want the result to be the same as the following for loop:

for i in 1...arr.length
  arr[i] += arr[i - 1]
end

Is it stylistically better to use the for loop here or do something like
this:

1.upto(arr.length - 1) {|i| arr[i] += arr[i - 1]}

Or is there another way of doing it that is better than both of these? I
feel like I should be able to do this using the each method but can't
figure out how to make the assignment work that way, and the upto
version is pretty short and sweet.

--
Posted via http://www.ruby-forum.com/\.

for i in 1...arr.length
arr[i] += arr[i - 1]
end

If you make a new array you could try something like this.
I do not know how fast it is but if you only have about 12 elements.....

p Array.new(arr.size){|x| arr[0..x].inject{|a,b| a+b}}

Harry

Josh Cheek wrote in post #1012707:

···

On Sat, Jul 23, 2011 at 8:41 PM, Marshall Farrier > <info@marshallfarrier.com>wrote:

  arr[i] += arr[i - 1]
version is pretty short and sweet.

--
Posted via http://www.ruby-forum.com/\.

It's hard to know how to answer this because you're overwriting the
values
of indexes that you use in calculations later on. This seems like it is
probably unintentional: If arr was [1,1,1], then are you expecting
[1,2,2]
-- the value at index 2 is calculated based on the original value at
index
1. Or are you expecting [1,2,3] -- the value at index 2 is calculated
based
on the new value at index 1?

If the former, then this is equivalent:
arr.each_cons(2).with_index(1) do |(left, right), index|
  arr[index] = left + right
end

If the latter, then this is equivalent:
(1...arr.length).each { |index| arr[index] += arr[index-1] }

Ok, sorry that my example muddled things so much. I did mean the latter.
The point of departure is that arr initially holds the (non-leap-year)
number of days in each month with 0 up front for month 0: [0, 31, 28,
31, 30, 31, 30, 31, 31, 30, 31, 30, 31]. Then I want to modify it so
that it holds the aggregate days in normal years up to the end of the
month in question. I then use this array for various date calculations.

--
Posted via http://www.ruby-forum.com/\.

Harry Kakueki wrote in post #1012785:

for i in 1...arr.length
arr[i] += arr[i - 1]
end

If you make a new array you could try something like this.
I do not know how fast it is but if you only have about 12 elements.....

p Array.new(arr.size){|x| arr[0..x].inject{|a,b| a+b}}

Harry

Tx for all the nice ideas! I agree that with an array this size speed
doesn't really matter except that it somehow figures into good
programming style--along with making good use of the specific features
and conventions of whatever language you are using.

···

--
Posted via http://www.ruby-forum.com/\.

Using each_with_index:

month_lengths = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

total_lengths = [0]

month_lengths.each_with_index do |length, i|
  total_lengths[i] = length + total_lengths[i - 1]
end

p total_lengths

Here's a version using inject:

month_lengths = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

total_lengths = [0]

month_lengths.inject do |length, total|
  total += length
  total_lengths << total
  total
end

p total_lengths

···

On Jul 24, 2011, at 9:25 AM, Marshall Farrier wrote:

Ok, sorry that my example muddled things so much. I did mean the latter.
The point of departure is that arr initially holds the (non-leap-year)
number of days in each month with 0 up front for month 0: [0, 31, 28,
31, 30, 31, 30, 31, 31, 30, 31, 30, 31]. Then I want to modify it so
that it holds the aggregate days in normal years up to the end of the
month in question. I then use this array for various date calculations.