我的代码使用来自MySQL数据库的信息来生成代表名单/ rota的哈希:
hash = {DateObject1 => "Fender", DateObject2 => "Leyla", DateObject3 => "Eiffel", DateObject4 => "Minkowski", DateObject5 => "Fender", DateObject6 => "Eiffel" etc.}
其中DateObjects
是类Date
,名称是String
。
然后,我有一系列名称,例如
itemarray = ["Eiffel", "Fender", "Leyla", "Minkowski", etc ]
我运行此代码,查找与给定名称关联的所有日期,并检测条件,例如两个结果日期在指定距离内。
class RotaIteration <
Struct.new(:whichiteration, :maxShifts1, :weekdays_too_close1, :weekends_too_close1, :weekday_Saturday_too_close1,
:shifts_too_close1, :max14days, :messes1, :iteration_cost1, :rotamd51)
end
def days_prox(date1,date2) # count all dates between 2 dates, not including start date
all_days=0
date = date2
while date > date1
all_days = all_days + 1
date = date-1;
end
all_days
end
itemarray.each do |item| $q1=hash.find_all {|k,v| v == item)
callsnum = $q1.length
if callsnum !=0
if callsnum > max_totShifts_90d then
no_solution[:maxShifts] +=1
no_solution[:iteration_cost] += max_ShiftCost
end
until item == callsnum
d1 = $q1[item-1][0]
d2 = $q1[item][0]
d1_daynum = d1.cwday
d2_daynum = d2.cwday
proximity = days_prox(d1,d2)
if proximity < min_any_prox then
no_solution[:shifts_too_close] +=1
no_solution[:iteration_cost] += shiftTooCloseCost
item +=1
elsif proximity < min_weekEnd_prox and (((6..7) === d1_daynum) and ((5..7) === d2_daynum)) then
no_solution[:weekends_too_close] +=1
no_solution[:iteration_cost] += weekendTooCloseCost
item +=1
elsif (3..7) === proximity and d1_daynum <=5 and d2_daynum == 6 then
no_solution[:weekday_Saturday_too_close] +=1
no_solution[:iteration_cost] += weekdaySatTooCloseCost
item +=1
elsif proximity < min_weekDay_prox and d1_daynum <=5 and d2_daynum <=5 then
no_solution[:weekdays_too_close] +=1
no_solution[:iteration_cost] += weekdayTooCloseCost
item +=1
else
item +=1
end
end
end
end
所以我可以根据它所具有的“问题”的数量以及这些特定问题的相对“成本”来比较给定的名册。
一旦我有几个名册模式,我可以做到:
rotaIt = RotaIteration.new
rotaIt.whichiteration = rota_iteration
rotaIt.maxShifts1 = no_solution[:maxShifts]
rotaIt.weekdays_too_close1 = no_solution[:weekdays_too_close]
rotaIt.weekends_too_close1 = no_solution[:weekends_too_close]
rotaIt.shifts_too_close1 = no_solution[:shifts_too_close]
rotaIt.messes1 = no_solution[:messes]
rotaIt.iteration_cost1 = no_solution[:iteration_cost]
rotaIt.rotamd51 = no_solution[:rotamd5]
rotaIterations.push(rotaIt) # array
然后我可以根据rotaIterations
类的属性对RotaIterations
数组进行排序。
我想要实现的目标是什么?
(1)查找与给定名称关联的所有日期 (2)检测条件,例如两个结果日期在指定距离内(并且与3或4个日期类似)
对马克·托马斯和其他人的第一篇文章表示道歉,这一点不明确,并且他们耐心地解开我的问题。
答案 0 :(得分:1)
最小化您最终编写的代码量并将自己绘制到复杂性角落的一种方法是将事物分解为对象。让我们从一个名册对象开始:
require 'date'
class Roster
attr_accessor :shifts
def initialize(hash={})
@shifts = hash
end
def add(date, name)
raise "Date already used" if shifts[date]
@shifts[date] = name
end
def names
@shifts.values.uniq
end
def shifts_for(name)
@shifts.select{|_,v| v==name}.keys
end
end
现在您可以这样使用它:
roster = Roster.new( {Date.today => 'Mark', Date.today + 1 => 'busfender'} )
roster.add(Date.today + 2, 'Mark')
roster.names #=> ['Mark', 'busfender']
roster.shifts_for('Mark') #=> [#<Date: 2018-01-21>, #<Date: 2018-01-23>]
roster.shifts_for('Mark').map(&:wday) #=> [0,2]
roster.shifts_for('Mark').any?(&:sunday?) #=> true
对于您想要执行的所有测试,范围有点大,但如果您在实施测试时遇到任何具体问题,则可以使用minimal, complete, and verifiable example提出单独的SO问题。
修改:我会帮助您处理第二个请求,确定在给定时间段内有多少请求。
假设您使用上面的Roster类,您可以执行以下操作:
diffs = roster.shifts_for('Claire').sort.each_cons(2).to_a.map{|(a,b)| (b-a).to_i}
#=> [2,3,2,4,5,2,5]
这为您提供了克莱尔每天班次变化之间的差异。 (键是each_cons(2)
,它将每个数组元素与下一个数组元素组合在一起。)因此,为了检查一周内是否有3个或更多个班次,您可以看到是否有任何3个跨度组,总计为7个或更少:
diffs.each_cons(3).map(&:sum).select{|span| span <= 7}.any?
如果任意三班组在7天的范围内,这将返回true
。
编辑2 :我刚刚注意到您的编辑声明您在MySQL中拥有此信息。几乎所有上述逻辑都应该在数据库中完成(可能使用ActiveRecord,DataMapper或续集)。通过提取到散列并执行散列操作,您将降低其效率并需要更多代码。