Forum: Ruby on Rails Multiple Sorts on an array, help with bad code smell

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
blinking bear (Guest)
on 2007-06-15 09:51
(Received via mailing list)
I have an Array of active record objects that I need to sort by two
attributes: similarity and activity, both are integers.

I'm currently doing this by first sorting the array on the similarity
field,
and then using group_by to group them groups with the same 'similarity'
and
then sorting those groups by activity.  Flattening this whole thing our
returns the original list sorted first by similarity and then by
activity.

Problem, this code is ugly, there has to be a cleaner way to do this.
Here
is the full method, its from a ActiveRecord model called 'Group'.

http://pastie.caboo.se/70645

  def related_groups
    #get the tags for this group
    tag_string = tags.collect(&:name)
    #find other groups with same tags
    groups_with_same_tags = Group.find_tagged_with(tag_string)
    if groups_with_same_tags.any?
      #delete self from list of groups
      groups_with_same_tags.delete(self)
      #delete duplicates
      groups_with_same_tags.uniq!
      #count how many tags they have in common (probably could cleanup
with
inject)
      groups_with_same_tags.each do |group|
        group.similarity = 0
        tags.each do |tag|
          group.similarity = group.similarity + 1 if group.tags.include
?(tag)
        end
      end
      #sort based on similarity of tags
      groups_with_same_tags = groups_with_same_tags.sort{ |x,y|
y.similarity<=>
x.similarity }
      #group into a 2D array grouped by similarity, make sure to
preserve
priority of the similarity
      grouped_groups =
groups_with_same_tags.group_by(&:similarity).sort{|x,y|
y[0] <=> x[0]}
      #sort the 2nd dimension of the array(which is an array of the
items of
a specific similarity) based on activity
      sorted_groups = grouped_groups.collect{ |g| g[1].sort{|x,y|
y.activity<=>
x.activity }}
      #flatten it out into a 1D array and return
      sorted_groups.flatten!
    else
      []
    end
  end


Thanks!
Steve R. (Guest)
on 2007-06-15 19:54
I haven't read the detail of your code (yet) but is there some reason
you can't form the array with

groups = Group.find(:all, :order => "similarity, activity")

steve
blinking bear (Guest)
on 2007-06-15 20:12
(Received via mailing list)
Steve - Unfortunately not, activity is not stored in the database.  It
is a
dynamic tally of how many tags it has in common with the original
object.

thanks
McPhage (Guest)
on 2007-06-16 01:20
(Received via mailing list)
Try something like:

groups_with_same_tags.sort! { |a, b| a.similarity == b.similarity ?
b.activity <=> a.activity : b.similarity <=> a.similarity }
blinking bear (Guest)
on 2007-06-16 02:18
(Received via mailing list)
perfect, tests pass, thanks!
McPhage (Guest)
on 2007-06-17 00:51
(Received via mailing list)
No problem--glad it worked.
This topic is locked and can not be replied to.