ROR 按时间上彼此的接近程度进行分组

发布于 2024-10-04 08:39:45 字数 608 浏览 2 评论 0原文

我已经很多年没有编写任何代码了,所以请原谅我愚蠢的问题,但如果项目按时间戳接近,我想对它们进行分组。我的意思是,例如,彼此相距不到 5 分钟的项目将被递归分组。我所说的递归是指第一个和最后一个项目彼此之间的距离不必少于 5 分钟,但它们之间需要有与前一个和下一个项目的距离都小于 5 分钟的项目。所以我需要的是一种将当前项目与前一个项目进行比较的方法,如果它们彼此之间的距离小于 5 分钟,则将当前项目添加到与前一个项目相同的组中。

ActiveRecord 解决方案会很好,因为项目数量非常大!

问题是使用group_by,我无法找到前一项,以便我可以比较时间戳。我尝试过一些像这样的愚蠢的东西只是为了比较这些项目:

a.group_by { |x| x.created_at == a[a.index(x)-1].created_at }

但我得到:

NoMethodError:nil:NilClass 的未定义方法“created_at”

有没有办法使用 group_by 来做到这一点,或者我需要“手动”迭代这些项目?由于项目数量相当大,有什么关于非常有效的解决方案的建议吗?

谢谢!

I haven't been coding anything for years, so please forgive my stupid questions, but I'd like to group items if they are close to each by timestamp. I mean that items that are for example less than 5 minutes from each other would be recursively grouped. By recursive I mean that the first and last item don't have to be less than 5 minutes away from each other, but they need to have items between them that are all closer than 5 minutes away from the previous and next item. So what I need is a way of comparing the current item with the previous item and if they are closer than 5 minutes away from each other, the current item is added to the same group as the previous item.

ActiveRecord solution would be nice, since the amount of items is very large!

The problem is that using group_by, I can't find the previous item, so that I could compare the timestamps. I've tried some silly stuff like this just to compare those items:

a.group_by { |x| x.created_at == a[a.index(x)-1].created_at }

But I get:

NoMethodError: undefined method `created_at' for nil:NilClass

Is there a way to do this using group_by, or do I need to iterate "manually" through those items? Any suggestions for a pretty efficient solution, as the number of items is quite large?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

凡尘雨 2024-10-11 08:39:45

Set 有一个 divide 函数来完成这个任务!你需要类似的东西:

Set[*a].divide { |x,y| (x-y).abs <= 5}

Set has a divide function that does exactly this! You'd need something like:

Set[*a].divide { |x,y| (x-y).abs <= 5}
千笙结 2024-10-11 08:39:45

我想不出任何在不调用真正嵌套的块的情况下按时间范围进行分组的方法。因此,如果我在哪里做类似的事情,我可能会在需要使用each_with_index方法显示它时进行分组。

我不知道你希望如何使用或呈现它,但假设你想要一个标题来显示每个组和每个项目,并在其自己的行上显示,它可能看起来像这样:

<% a.each_with_index do |item, index| %>
  <if index == 0 or ( item.created_at - a[index-1].created_at ) > 300.seconds %>
    <h1><%= item.created_at %></h1>
  <% end %>
  <p><%= item.title %></p>
<% end %>

这可能不是你想要的使用它,但它显示了如何使用each_with_index的示例。

I can't think of any way to group by a time range without invoking a really nested block. So if I where to do something similar, I would probably make that grouping when it was time to display it by using the each_with_index method.

I don't know how you want it used or presented but say that you want a header to display each group and each item where to be displayed on its own row, it could look something like this:

<% a.each_with_index do |item, index| %>
  <if index == 0 or ( item.created_at - a[index-1].created_at ) > 300.seconds %>
    <h1><%= item.created_at %></h1>
  <% end %>
  <p><%= item.title %></p>
<% end %>

This is probably nothing like you want to use it, but it shows an example of how each_with_index can be used.

狠疯拽 2024-10-11 08:39:45

你说你想根据他们彼此之间的距离进行分组。您想要的是按 #created_at 值的子集进行分组,因此:

require "rubygems"
require "active_support/core_ext/array"
require "ostruct"
require "pp"

o1 = OpenStruct.new(:created_at => Time.local(2010, 11, 24, 20,  1, 0, 0))
o2 = OpenStruct.new(:created_at => Time.local(2010, 11, 24, 20,  2, 0, 0))
o3 = OpenStruct.new(:created_at => Time.local(2010, 11, 24, 20,  6, 0, 0))
o4 = OpenStruct.new(:created_at => Time.local(2010, 11, 24, 20, 13, 0, 0))

a = [o1, o2, o3, o4]

grouped = a.group_by do |obj|
  time = obj.created_at
  Time.local(time.year, time.month, time.day, time.hour, (time.min / 5).floor, 0)
end

pp grouped.map {|val, arr| [val, arr.map {|obj| obj.created_at.to_s }] }

返回:

$ ruby a.rb
[[Wed Nov 24 20:02:00 -0500 2010, ["Wed Nov 24 20:13:00 -0500 2010"]],
 [Wed Nov 24 20:00:00 -0500 2010,
  ["Wed Nov 24 20:01:00 -0500 2010", "Wed Nov 24 20:02:00 -0500 2010"]],
 [Wed Nov 24 20:01:00 -0500 2010, ["Wed Nov 24 20:06:00 -0500 2010"]]]

每个封闭数组的第一个值是键(以 5 分钟为一组的分钟),值是实际的 ActiveRecord 对象。为了便于阅读,我映射到了 Time 的字符串版本,但这是相同的想法。

另请记住,#group_by 生成一个与原始数组排序相同的数组,因此您的排序约束得到保留 - 您不需要使用该数组。

You say you want to group by how close they are to each other. What you want is to group by a subset of the #created_at value, thus:

require "rubygems"
require "active_support/core_ext/array"
require "ostruct"
require "pp"

o1 = OpenStruct.new(:created_at => Time.local(2010, 11, 24, 20,  1, 0, 0))
o2 = OpenStruct.new(:created_at => Time.local(2010, 11, 24, 20,  2, 0, 0))
o3 = OpenStruct.new(:created_at => Time.local(2010, 11, 24, 20,  6, 0, 0))
o4 = OpenStruct.new(:created_at => Time.local(2010, 11, 24, 20, 13, 0, 0))

a = [o1, o2, o3, o4]

grouped = a.group_by do |obj|
  time = obj.created_at
  Time.local(time.year, time.month, time.day, time.hour, (time.min / 5).floor, 0)
end

pp grouped.map {|val, arr| [val, arr.map {|obj| obj.created_at.to_s }] }

Which returns:

$ ruby a.rb
[[Wed Nov 24 20:02:00 -0500 2010, ["Wed Nov 24 20:13:00 -0500 2010"]],
 [Wed Nov 24 20:00:00 -0500 2010,
  ["Wed Nov 24 20:01:00 -0500 2010", "Wed Nov 24 20:02:00 -0500 2010"]],
 [Wed Nov 24 20:01:00 -0500 2010, ["Wed Nov 24 20:06:00 -0500 2010"]]]

The first value of each enclosed Array is the key (minute in groups of 5 minutes), and the values are the actual ActiveRecord objects. For readability, I've mapped to the String version of Time, but it's the same idea.

Also remember that #group_by generates an Array ordered the same as the original Array, thus your ordering constraints are kept - you don't need to resort the Array.

护你周全 2024-10-11 08:39:45

我建议在数据库端使用类似的方法来执行此操作:

group_by(to_nearest_ Five_minutes(updated_date))

I'd recommend doing it on the database side using something like:

group_by(to_nearest_five_minutes(updated_date))

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文