Friday, June 22, 2007

A better group_by "in_groups_by" for ActiveRecord

Background

Active record's find returns an array, you can use group_by to put the result into a groups. However group_by returns a hash, a hash does not have any order, When you iterate thru the hash it comes out in any order.

Better Approach

Write a function to return a array of records grouped by some critiera (Like in_groups_of). Now you can simply iterate thru using each and each. In my implementation I have assumed the data is already ordered

The Code

class Array
  def in_groups_by
    # Group elements into individual array's by the result of a block
    # Similar to the in_groups_of function.
    # NOTE: assumes array is already ordered/sorted by group !!
    curr=nil.class 
    result=[]
    each do |element|
       group=yield(element) # Get grouping value
       result << [] if curr != group # if not same, start a new array
       curr = group
       result[-1] << element
    end
    result
  end
end

Go on Give it a go, Copy and paste the below code into say the bottom of "environment.rb", re-cycle the server, and try

An Example

def customers_grouped_by_country
  ds=Customer.find(:all, :order => :order=>"county_id")
  ds.in_groups_by(&:county_id)
  # or the alternative syntax 
  # ds.in_groups_by { |r| r.country_id }
end

<% customers_grouped_by_country.each do |group| %>
  <h1>Country <%= group[0].country_id></h1>
  <% group.each do |e| %>
    <p><%= e.name %></p>
  <% end %>
<% end >

2 comments:

Unknown said...

Thank you for this snippet. It was exactly what I needed.

Anonymous said...

Thanks, works perfectly !

Google