Uniq by object attribute in Ruby

Solution 1:

Use Array#uniq with a block:

@photos = @photos.uniq { |p| p.album_id }

Solution 2:

Add the uniq_by method to Array in your project. It works by analogy with sort_by. So uniq_by is to uniq as sort_by is to sort. Usage:

uniq_array = my_array.uniq_by {|obj| obj.id}

The implementation:

class Array
  def uniq_by(&blk)
    transforms = []
    self.select do |el|
      should_keep = !transforms.include?(t=blk[el])
      transforms << t
      should_keep
    end
  end
end

Note that it returns a new array rather than modifying your current one in place. We haven't written a uniq_by! method but it should be easy enough if you wanted to.

EDIT: Tribalvibes points out that that implementation is O(n^2). Better would be something like (untested)...

class Array
  def uniq_by(&blk)
    transforms = {}
    select do |el|
      t = blk[el]
      should_keep = !transforms[t]
      transforms[t] = true
      should_keep
    end
  end
end

Solution 3:

Do it on the database level:

YourModel.find(:all, :group => "status")