Ruby / Rails - 使用group_by进行高级分组

时间:2012-01-11 15:33:21

标签: ruby ruby-on-rails-3

我有一个名为event_recurrences的模型,它包含2个重要的列event_idcached_schedule

cached_schedule包含一系列日期

event_id用于引用事件

我需要

  1. 获取所有event_recurrence对象@something.event_recurrences - 完成

  2. 浏览每个重复对象并获取event_id和所有 来自cached_schedule

  3. 的日期
  4. 遍历每个月,并吐出如下列表

  5. event_id日期

    event_id日期

    event_id日期

    二月

    event_id日期

    ......等等

    回顾event_id位于event_recurrence.event_id的{​​{1}}日期event_id位于event_recurrence.cached_schedule

    内的数组中

    有些我有一些不完整的代码可供使用...

    此代码可成功运行,使用event_recurrence字段按月显示每个created_at对象。

    在我的控制器中

    @schedule_months = @something.event_recurrences.order("created_at DESC").group_by { |e| e.created_at.beginning_of_month }
    

    在我看来

    <% @schedule_months.keys.sort.each do |month| %>  
        <div class="month">
            <%= month.strftime("%B %Y") %>
        </div> 
      <% for event in @schedule_months[month] %>  
        <li><%= event %></li>
      <% end %>  
    <% end %>
    

    提前致谢。

    此致,jBeas

1 个答案:

答案 0 :(得分:3)

您的问题中缺少一些详细信息...例如,cached_schedule中的日期是否可以跨越多个月,或者它们是否都保证在同一个月内?

如果你只想使用核心Ruby:

dates = []
@something.event_recurrences.each do |er| 
  er.cached_schedule.each { |date| dates << [date, er.event_id] }
end
@event_dates = dates.group_by { |(date,event_id)| date.mon }

然后在视图中:

<% @event_dates.keys.sort.each do |month| %>
  <div class="month"> <%= month.strftime("%B %Y") %></div>
   <% @event_dates[month].each do |(date,event_id)| %>
      <li><%= date %> <%= event_id %></li>
   <% end %>
<% end %>

您可能需要根据具体情况稍微调整一下代码,但这应该会给您一些想法。请注意使用解构赋值:@event_dates[month].each do |(date,event_id)|。这样可以节省一行代码并更清楚地表达代码的作用。

如果您不介意将自己的扩展添加到核心Ruby类,则可以使此代码更清晰,更简洁。我经常使用一种方法,我称之为mappend

module Enumerable
  def mappend
    result = []
    each { |a| enum = yield a; enum.each { |b| result << b } if enum }
    result
  end
end

该名称是mapappend的混合 - 它类似于map,但它希望映射块的返回值也为Enumerable,并且它将所有返回的Enumerable“追加”到一个Array中。有了这个,你可以写:

@event_dates = @something.event_recurrences.mappend { |er| er.cached_schedule.map { |date| [date, er.event_id] }}.group_by { |(date,event_id)| date.mon }

好的,对于一行来说可能很多,但你明白了:它可以避免使用中间变量来累积结果。

更新:mappend这样的东西现在是Ruby核心库的一部分!它被称为flat_map

相关问题