Ruby,时间数组中的时间间隔

3
我可以帮助您进行翻译。以下是您需要翻译的内容:

我有一个查询(针对MongoDB数据库),返回已经进行了映射减少的对象,这些对象每15分钟汇报一次,但问题在于,如果其中一个服务器发生关键错误,则该时间段将无法计算。

以这个数组为例:

[
  {:timestamp=>2011-09-26 19:00:00 UTC, :count=>318},
  {:timestamp=>2011-09-26 19:15:00 UTC, :count=>308},
  {:timestamp=>2011-09-26 19:30:00 UTC, :count=>222},
  {:timestamp=>2011-09-26 19:45:00 UTC, :count=>215},
  {:timestamp=>2011-09-26 20:00:00 UTC, :count=>166},
  {:timestamp=>2011-09-26 21:15:00 UTC, :count=>149},
  {:timestamp=>2011-09-26 21:30:00 UTC, :count=>145},
  {:timestamp=>2011-09-26 21:45:00 UTC, :count=>107},
  {:timestamp=>2011-09-26 22:00:00 UTC, :count=>137},
  {:timestamp=>2011-09-26 22:15:00 UTC, :count=>135},
  {:timestamp=>2011-09-26 22:30:00 UTC, :count=>191},
  {:timestamp=>2011-09-26 22:45:00 UTC, :count=>235}
]

您会注意到时间范围中缺少时间:

{:timestamp=>2011-09-26 20:15:00 UTC},
{:timestamp=>2011-09-26 20:30:00 UTC},
{:timestamp=>2011-09-26 20:45:00 UTC},
{:timestamp=>2011-09-26 21:00:00 UTC}

如何将顶部作为输入,并推断出这些将是缺失的行?时间增量将始终为15分钟,实际上,它是一个真正的日期对象,而不是像那样的字符串。

我无法想象如何迭代它。

任何帮助都将非常感激。

3个回答

3
我能想到最简单的方法是按时间戳对数组进行排序,然后执行以下操作:
missing_times = []
reports.each_with_index do |report, index|
  if reports[index + 1]
    if report.timestamp.advance(minutes: 15) < report[index + 1].timestamp
      i = 0
      while(report.timestamp.advance(minutes: 15*i) < report[index+1].timestamp)
        missing_times << report.timestamp.advance(minutes: 15*i)
      end
    end
  end
end

我之前写过类似的代码来查找预约时间中的半小时空隙。

尽管看起来我的解决方案会在报告的开始时间(reports.first)和结束时间(reports.last)之间的15分钟增量上多次循环,但实际上它只会在所有可用增量之间循环一次。


我在实现这个功能时遇到了一些问题,在 if report[:timestamp].advance(minutes: 15) < report[index + 1][:timestamp] 这一行中,小于号后面的 report[index + 1] 是 nil 吗?当我将其更改为我认为应该是的 reports[index + 1] 时,程序会一直运行。你有什么想法吗? - JP Silvashy

1

在处理大型数据集时,与其进行多重循环,不如创建一个时间跨度数组,每15分钟增加一次,并针对您的报告集进行比较并删除任何匹配项,这将更加高效。

start_time = report.first
span = ((report.last - start_time)/60/15).to_i   # this gives the number of 15min blocks
test_array = []
span.times do |i|
  test_array << start_time + i*15.minutes
end
report.each do |r|
  test_array.delete(r)   # or in your case, r.timestamp
end

我认为它可以工作,但是我想不出一个好的方法来制作一个时间戳的参考表,所以我通过一些hack方法实现了它。


1
只有当间隔大于15分钟时,我的答案才会循环,如果没有间隔,我的解决方案只会在数组上迭代一次。此外,我的数组不会遍历所有可能的时间,只会填充间隙。您的解决方案将始终具有2个循环,一个用于加载时间跨度,另一个用于遍历所有元素。当没有间隔时,您的解决方案将两次循环遍历所有元素。我的最坏情况总是会在所有可用增量上循环一次,等于您的“span.times”循环。 - Dan McClain
此外,test_array.delete 迭代整个数组以查找要删除的元素,请参见代码:http://www.ruby-doc.org/core/classes/Array.src/M000255.html,因此您的代码是 O(n^2),每次调用 delete 时,您都可能循环遍历整个数组。 - Dan McClain

0

从第一个时间戳开始,每次增加15分钟,验证该条目是否存在,并继续进行,直到达到最后一个时间戳。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接