Como criar um infinito enumerável vezes?
-
22-09-2019 - |
Pergunta
Quero poder ter um objeto que se estende enumerável em Ruby para ser uma lista infinita de segundas -feiras (por exemplo).
Então isso cederia: 29 de março, 5 de abril, 12 de abril ...... etc
Como posso implementar isso em Ruby?
Solução
Em 1.9 (e provavelmente versões anteriores usando backports
), você pode criar facilmente o enumerador:
require 'date'
def ndays_from(from, step=7)
Enumerator.new {|y|
loop {
y.yield from
from += step
}
}
end
e = ndays_from(Date.today)
p e.take(5)
#=> [#<Date: 2010-03-25 (4910561/2,0,2299161)>, #<Date: 2010-04-01 (4910575/2,0,2299161)>, #<Date: 2010-04-08 (4910589/2,0,2299161)>, #<Date: 2010-04-15 (4910603/2,0,2299161)>, #<Date: 2010-04-22 (4910617/2,0,2299161)>]
Outras dicas
Armazene a Date
como variável de instância, inicializada em uma segunda -feira. Você implementaria um each
método que incrementa a data armazenada em 7 dias usando date += 7
.
Você poderia fazer algo estendendo a data ...
#!/usr/bin/ruby require 'date' class Date def current_monday self - self.wday + 1 end def next_monday self.current_monday + 7 end end todays_date = Date.today current_monday = todays_date.current_monday 3.times do |i| puts current_monday.to_s current_monday = current_monday.next_monday end 2010-03-22 2010-03-29 2010-04-05 2010-04-12
... com os avisos usuais sobre a extensão das classes base, é claro.
Você pode estender a classe de data com o método NW segundas
class Date
def self.mondays(start_date=Date.today, count=10)
monday = start_date.wday > 1 ? start_date - start_date.wday + 8 : start_date - start_date.wday + 1
mondays = []
count.times { |i| mondays << monday + i*7}
mondays
end
end
Date.mondays retornará por padrão padrão de segundas -feiras com 10 elementos da segunda -feira mais próxima até o momento.Today. Você pode passar os parâmetros:
Date.mondays(start_date:Date, count:Integer)
start_date - ponto de partida para encontrar a contagem de segunda -feira mais próxima - número de segundas -feiras que você está procurando
Ou seja:
Date.mondays(Date.parse('11.3.2002'))
Date.mondays(Date.parse('11.3.2002'), 30)
module LazyEnumerable
extend Enumerable
def select(&block)
lazily_enumerate { |enum, value| enum.yield(value) if
block.call(value) }
end
def map(&block)
lazily_enumerate {|enum, value| enum.yield(block.call(value))}
end
def collect(&block)
map(&block)
end
private
def lazily_enumerate(&block)
Enumerator.new do |enum|
self.each do |value|
block.call(enum, value)
end
end
end
end
...........
class LazyInfiniteDays
include LazyEnumerable
attr_reader :day
def self.day_of_week
dow = { :sundays => 0, :mondays => 1, :tuesdays => 2, :wednesdays =>
3, :thursdays => 4, :fridays => 5, :saturdays => 6, :sundays => 7 }
dow.default = -10
dow
end
DAY_OF_WEEK = day_of_week()
def advance_to_midnight_of_next_specified_day(day_sym)
year = DateTime.now.year
month = DateTime.now.month
day_of_month = DateTime.now.day
output_day = DateTime.civil(year, month, day_of_month)
output_day += 1 until output_day.wday == DAY_OF_WEEK[day_sym]
output_day
end
def initialize(day_sym)
@day = advance_to_midnight_of_next_specified_day(day_sym)
end
def each
day = @day.dup
loop {
yield day
day += 7
}
end
def ==(other)
return false unless other.kind_of? LazyInfiniteDays
@day.wday == other.day.wday
end
end