Last night I removed my custom tagging system, and converted to acts_as_taggable. I’m thinking DHH’s code is probably a little bit better than mine (just a hunch). I’m also converting my tag methods to use some of the other nice things acts_as_taggable provides, such as: find_tagged_with, tag_names, and one of the reasons for this post, tags_count.
The tags to the left are now being pulled via the tags_count method, but I run into a problem. That method returns a hash where the key is the tag name, and the value is the post count (i.e. [[“rails”, 38],[“personal”, 37], ...]). That’s great and all, but I need to sort it in descending order, based on the value and not the key. So here’s what I’m doing:
1 2 3 | def self.get_popular(options={}) Post.tags_count(:limit => (options[:limit].to_i || 10)).invert.sort.reverse end |
The #invert method of the Hash class essentially swaps the key => value pairs to become value => key pairs. This allows me to call #sort which will then sort by the value (aka the count) rather than the key (aka the name). And at the end of this chain we have #reverse which just gives me the descending order. Seems to work, right? Well, almost.
The problem I’m having is when two tags have the same post count. It seems to then grab only one of them (the first in the alphabet?) I don’t exactly know if this is something I’m worried about fixing, but it makes me feel as though I’m not in control of the code, which I don’t necessarily like. Plus, I don’t know that I fully understand what’s happening, here. It’s ignoring the redundant values in the sort. Thoughts/ideas are welcome, even if it means a new method to get the posts-per-tag count.
01
Chris on Thu Apr 19 at 04:35AM
Just quickly looking at this, if I recall,
invertwill return a hash. If two tags have the same count value, and they are inverted, you end up assigning the same key (previously the value) twice. Hash keys are unique, hence you only get one of them in return.Assuming
tags_countreturns something like{ :tag => count, :tag2 => count }, you can do something like this (untested):Post.tags_count(..).to_a.sort { |a,b| a[1] <=> b[1] }And if you need them in the opposite order, make the comparison
b[1] <=> a[1]or use.reverseafter the block.02
Ryan on Thu Apr 19 at 05:36AM
You are absolutely correct. I was indeed duplicating keys (not sure why that didn’t cross my mind).
And the untested code in your comment works just like I need (but I removed the
.to_asince.sortconverts the hash to an array, anyway). Thanks for clearing that up.03
Chris on Thu Apr 19 at 06:24AM
Yeah, I put
to_ajust to be safe, but I was pretty suresortwould convert it for you. Glad it worked out ;-)