views:

78

answers:

1

Given a minimum integer and maximum integer, I want to create an array which counts from the minimum to the maximum by two, then back down (again by two, repeating the maximum number).

For example, if the minimum number is 1 and the maximum is 9, I want [1, 3, 5, 7, 9, 9, 7, 5, 3, 1].

I'm trying to be as concise as possible, which is why I'm using one-liners.

In Python, I would do this:

range(1, 10, 2) + range(9, 0, -2)

In Ruby, which I'm just beginning to learn, all I've come up with so far is:

(1..9).inject([]) { |r, num| num%2 == 1 ? r << num : r }.reverse.inject([]) { |r, num| r.unshift(num).push(num) }

Which works, but I know there must be a better way. What is it?

+3  A: 
(1..9).step(2).to_a + (1..9).step(2).to_a.reverse

But shorter would be

Array.new(10) { |i| 2 * [i, 9-i].min + 1 }

if we're code golfing :)

rampion
Oh, how could I forget `Range#step`!
Marc-André Lafortune
Range#step seems to [expect a block](http://ruby-doc.org/core/classes/Range.html#M000695) - the first example, while otherwise exactly what I was hoping for, is throwing an error for me. (`no block given (LocalJumpError)`)
Kiwi
@Kiwi: You're using Ruby 1.8.6. Upgrade to 1.8.7+ or `include "backports"`
Marc-André Lafortune
@Kiwi: In 1.8.7, a bunch of iterator methods that required blocks in 1.8.6 were modified to return `Enumerator`s when not given blocks.
rampion
Wonderful, thanks! I was under the impression that the documentation was up-to-date, but I don't think it is. Thanks for your help.
Kiwi
If you wish to code-golf/eliminate-duplication for the first example, you can do: `(a = (1..9).step(2).to_a) + a.reverse`. Whether or not this is better will probably depend upon how much C you did in a previous life.
Wayne Conrad
@Kiwi: Yeah, the doc was quite incomplete with respect to returning enumerators. Fixed for 1.9.2+, but I don't have the courage to backport http://github.com/ruby/ruby/commit/4afa9e to the 1.8 line.
Marc-André Lafortune