Given n
, I want to create an array from 0
to n
:
10.make_array #=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
It should also work if n
is negative:
-10.make_array #=> [0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10]
I have written this code, but I think I made it more complicated than necessary (it doesn't work for negative numbers, yet):
class Fixnum
define_method(:make_array) do
my_array = []
self.times() do |count|
self.>(0)
my_array.push(count)
end
my_array.push(self)
my_array
end
end
Is there an easier way or short-cut to do the same thing, and any suggestions on how to handle a negative number?
Use a Range
:
(0 .. 10).to_a
#=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Handling negative numbers is not a problem:
(-10 .. -1).to_a
#=> [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1]
To support negative numbers, you could use upto
and downto
along with a condition:
(I'm showing a stand-alone method here instead of patching Integer
)
def make_array(n)
if n > 0
0.upto(n).to_a
else
0.downto(n).to_a
end
end
The above creates an enumerator that's converted to an array using Enumerable#to_a
.
You might want to skip the intermediate object (the enumerator) by directly calling Array::new
- it creates an array with the given number of elements:
n = 3
Array.new(n) #=> [nil, nil, nil]
If a block is given, it passes each element's index to the block and we are supposed to returns its value. The index is in fact just what we want, so we can simply return it:
Array.new(n) { |i| i } #=> [0, 1, 2]
As you can see, Array.new(n)
returns n
elements, but we need n + 1
, so let's fix that:
Array.new(n + 1) { |i| i } #=> [0, 1, 2, 3]
Unfortunately, Array::new
doesn't accept a negative size:
Array.new(-3) #=> negative array size (ArgumentError)
So for negative n
we have to pass -n
and also return -i
:
n = -3
Array.new(-n + 1) { |i| -i } #=> [0, -1, -2, -3]
As a method:
def make_array(n)
if n > 0
Array.new(n + 1) { |i| i }
else
Array.new(-n + 1) { |i| -i }
end
end
Let's try to avoid the duplication.
Converting n
to a positive number is easy using abs
:
3.abs #=> 3
-3.abs #=> 3
Applied to our code:
n = 3
Array.new(n.abs + 1) { |i| i } #=> [0, 1, 2, 3]
n = -3
Array.new(n.abs + 1) { |i| i } #=> [0, 1, 2, 3]
For the block, we could use a ternary if
:
n = 3
Array.new(n.abs + 1) { |i| n > 0 ? i : -i } #=> [0, 1, 2, 3]
n = -3
Array.new(n.abs + 1) { |i| n > 0 ? i : -i } #=> [0, -1, -2, -3]
We can even remove the condition by using the spaceship operator a <=> b
. It determines whether a
is less than, equal to, or greater than b
by returning -1
, 0
or +1
, respectively.
More specifically, for Fixnum#<=>
, n <=> 0
returns 1
if n
is greater than 0
, and -1
if n
is less than 0
:
3 <=> 0 #=> 1
-3 <=> 0 #=> -1
We can use <=>
's result in our block to multiply i
with:
Array.new(n.abs + 1) { |i| i * (n <=> 0) }
This is equivalent to i * 1
(if n > 0
) or i * -1
(if n < 0
).
(There's a third return value: n <=> 0
returns 0
if n
is equal to 0
but that doesn't matter, because in that case the resulting array is [0]
and 0 * 0
is still 0
)
As a method:
def make_array(n)
Array.new(n.abs + 1) { |i| i * (n <=> 0) }
end
Although it is short, this method became quite complex and it's not obvious what is is doing. Therefore, I would prefer the first method (the one using upto
and downto
) because of its simplicity.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With