Declaring an Integer Range with Step != 1 in Ruby

Declaring an integer Range with step != 1 in Ruby

You can't declare a Range with a "step". Ranges don't have steps, they simply have a beginning and an end.

You can certainly iterate over a Range in steps, for example like this:

(2..100).step(2).reverse_each(&method(:p))

But if all you want is to iterate, then what do you need the Range for in the first place? Why not just iterate?

100.step(2, -2, &method(:p))

This has the added benefit that unlike reverse_each it does not need to generate an intermediate array.

Create array in Ruby with begin value, end value and step for float values

For floats with custom stepping you can use Numeric#step like so:

-1.25.step(by: 0.5, to: 1.25).to_a
# => [-1.25, -0.75, -0.25, 0.25, 0.75, 1.25]

If you are looking on how to do this with integer values only, see this post or that post on how to create ranges and simply call .to_a at the end. Example:

(-1..1).step(0.5).to_a
# => [-1.0, -0.5, 0.0, 0.5, 1.0]

Ruby's range step method causes very slow execution?

Assuming MRI and Rubinius use similar methods to generate the range the basic algorithm used with all the extraneous checks and a few Fixnum optimisations etc. removed is:

class Range
def each(&block)
current = @first
while current < @last
yield current
current = current.succ
end
end

def step(step_size, &block)
counter = 0
each do |o|
yield o if counter % step_size = 0
counter += 1
end
end
end

(See the Rubinius source code)

For a Time object #succ returns the time one second later. So even though you are asking it for just each week it has to step through every second between the two times anyway.

Edit: Solution

Build a range of Fixnum's since they have an optimised Range#step implementation.
Something like:

date_counter = Time.mktime(2011,01,01,00,00,00,"+05:00")
@weeks = Array.new

(date_counter.to_i..Time.now.to_i).step(1.week).map do |time|
Time.at(time)
end.each do |week|
logger.debug "WEEK: " + week.inspect
@weeks << week
end

How can I iterate over a reversed range with a specific step in Ruby?

Why don't you use Numeric#step:

From the docs:

Invokes block with the sequence of numbers starting at num, incremented by step (default 1) on each call. The loop finishes when the value to be passed to the block is greater than limit (if step is positive) or less than limit (if step is negative). If all the arguments are integers, the loop operates using an integer counter. If any of the arguments are floating point numbers, all are converted to floats, and the loop is executed floor(n + n*epsilon)+ 1 times, where n = (limit - num)/step. Otherwise, the loop starts at num, uses either the < or > operator to compare the counter against limit, and increments itself using the + operator.


irb(main):001:0> 10.step(0, -2) { |i| puts i }
10
8
6
4
2
0

How can I convert a step-down range to array?

1000.downto(0).each { |i| ... }        

what function to use in ruby to simulate a for

You want step. It is used like this:

10.step(1, -2) do |x|
puts x
end

This results in:

10
8
6
4
2

calling .each{} on IntRange returns the range not each integer

Use parentheses not brackets:

(1..10).each{println it}

[1..10] is a list of length 1 containing a single range.

Generate a custom date range

This cannot be done with a Range as @sawa already pointed out.

I think you need to use an array filled with qualified days:

def working_days(number)
[].tap do |days|
date = Date.today
while days.size < number
days << date unless date.sunday? || date.saturday?
date = date.next
end
end
end

working_days(5)
#=> [02 Dec 2015, 03 Dec 2015, 04 Dec 2015, 07 Dec 2015, 08 Dec 2015]


Related Topics



Leave a reply



Submit