Ruby 检测重复事件中的冲突

Ruby 检测重复事件中的冲突,ruby,calendar,constraints,recurrence,Ruby,Calendar,Constraints,Recurrence,我正在编写一个需要检查冲突的日历应用程序 在重复条目之间。每个条目对象都有一个recurrences()方法 它返回一个范围数组-每个范围包含开始和结束 每次未来发生的次数 我需要检查新条目和现有条目之间是否存在冲突。我是 执行此操作时,请检查新的 条目与现有条目将来出现的冲突: def conflicts?(other) conflicts = 0 recurrences.each do |my_rec| other.recurrences.each do |other_rec

我正在编写一个需要检查冲突的日历应用程序 在重复条目之间。每个条目对象都有一个recurrences()方法 它返回一个范围数组-每个范围包含开始和结束 每次未来发生的次数

我需要检查新条目和现有条目之间是否存在冲突。我是 执行此操作时,请检查新的 条目与现有条目将来出现的冲突:

def conflicts?(other)
  conflicts = 0
  recurrences.each do |my_rec|
    other.recurrences.each do |other_rec|
      start, finish = other_rec.first, other_rec.last
      conflicts += 1 if my_rec.include?(start) || my_rec.include?(finish)
    end
  end
  conflicts > 0
end
recurrences()默认返回开始时间之间的所有事件 和开始时间+1年

问题是这种方法不是很有效。仅比较两个条目,每个条目在一年内每天重复一次,就可以进行365*365次比较(在我的机器上,这需要4秒以上的时间)。可以有任意数量的现有条目将新条目与so进行比较 我现在的方法是无用的

我没有计算机科学或数学背景,但我一直 在阅读各种算法教科书时,我一直找不到答案 优化方法的方法。还有其他人有什么想法吗

谢谢


Dave

首先,您可以通过提前返回函数来改善这一点:

def conflicts?(other)
  conflicts = 0
  recurrences.each do |my_rec|
    other.recurrences.each do |other_rec|
      start, finish = other_rec.first, other_rec.last
      return true if my_rec.include?(start) || my_rec.include?(finish)
    end
  end
  false
end
但是,这不会提高算法的平均性能,但在发生冲突时只会导致一次比较。唯一的选择是尽早检测“简单”碰撞。很像

  • 将重复类型(每周、每天、每月)存储到重复对象中
  • 如果这两种情况每天都会发生,那么找出第一天可能发生冲突的地方。示例:每日,a:一月至七月,b:五月至十月应仅检查五月一日是否存在时间冲突。如果没有发生冲突,则不需要检查其他冲突
  • 对不同星座(周-周、日-周、日-年)执行相同操作
  • 避免写
    周日
    周日
    -
    周日(x,y)
    周日(y,x)
    相同
  • 如果找不到匹配的方法,则必须使用上面给出的方法作为备用方法
正如您所见,后者的工作量要大得多,最坏情况下的执行时间可能是相同的(因为它使用原始算法作为后备)。最坏的情况可能是由“不规则的”恢复(例如,每天一小时后)引起的。

一些想法:

  • 使用从日历日期指向该日期所有条目列表的数据结构。然后在该日期的条目列表中查找冲突
  • 看看一天中的一周——周一的重复条目永远不会与周三的条目发生冲突(包含在第一个想法中)
  • 使用过期日期-检查冲突时,仅检查符合较早过期的条目的日期。 你可能会从中得到一些灵感

  • 假设重复事件是可排序的,您可以按O(n*log(n)对它们进行排序,并且只与相邻事件进行比较。下面是一个开始:

    def conflicts?(other)
     conflicts = 0
     # Generate all recurrences and sort
     all_recurrences = recurrences + other.recurrences
     all_recurrences.sort!
    
     # Keep track of what immediate neighbors could be conflicting
     conflicting = []
     all_recurrences.each do |my_rec| 
         conflicting.each do |other_rec| do
           start, finish = other_rec.first, other_rec.last
           if my_rec.include?(start) || my_rec.include?(finish) then
              # TODO update conflicting array: add my_rec + other_rec if conflicting
              conflicts += 1
           else 
              # TODO remove other_rec if not conflicting
           end
         end
     end
     conflicts > 0
    end
    
    require 'set' #ruby standard lib
    first_dates  = Set.new [1,2]  #where 1 and 2 are your sample dates, in an array
    second_dates = Set.new [2,3]  #where 2 and 3 are your sample dates,
    first_dates.intersection( second_dates ).empty?  #if empty, then no conflict