Ruby group по месяцам и годам

#ruby #activerecord

#ruby #activerecord

Вопрос:

У меня есть (ar) класс PressClipping, состоящий из заголовка и поля даты.

Я должен отображать это так:

Заголовок 1
февраля 2011 года

январь
2011 года …

Какой самый простой способ выполнить эту группировку?

Комментарии:

1. Пожалуйста, обновите свой код.

Ответ №1:

Вот некоторые выходные данные Haml, показывающие, как выполнить итерацию с помощью Enumerable#group_by :

 - @clippings_by_date.group_by{|c| c.date.strftime "%Y %b" }.each do |date_str,cs|
  %h2.date= date_str
  %ul.clippings
    - cs.each do |clipping|
      %li <a href="...">#{clipping.title}</a>
  

Это дает вам хэш, где каждый ключ представляет собой форматированную строку даты, а каждое значение представляет собой массив вырезок для этой даты. Это предполагает Ruby 1.9, где хэши сохраняются и повторяются в порядке вставки. Если у вас версия ниже 1.8.x, вместо этого вам нужно будет сделать что-то вроде:

 - last_year_month = nil
- @clippings_by_date.each do |clipping|
  - year_month = [ clipping.date.year, clipping.date.month ]
  - if year_month != last_year_month
    - last_year_month = year_month
    %h2.date= clipping.date.strftime '%Y %b'
  %p.clipping <a href="...>#{clipping.title}</a>
  

Я полагаю, вы могли бы воспользоваться group_by версией 1.8 вот так (просто используя чистый Ruby сейчас, чтобы донести суть):

 by_yearmonth = @clippings_by_date.group_by{ |c| [c.date.year,c.date.month] }
by_yearmonth.keys.sort.each do |yearmonth|
  clippings_this_month = by_yearmonth[yearmonth]
  # Generate the month string just once and output it
  clippings_this_month.each do |clipping|
    # Output the clipping
  end 
end
  

Комментарии:

1. Большое спасибо, я не знал, что могу передать лямбда-выражение в предложение group_by.

2. @Jan Хех, я только что изменил ответ, чтобы удалить лямбда. В общем, однако, любой метод, который принимает блок, может вместо этого передавать proc / lambda, используя my_method(arg1,arg2,...,argn,amp;mylambda)