I'm trying to optimize this bit of code and I thought I'd throw it out here to see if anyone has any ideas. I've been testing the performance using Benchmark.measure {...}
and wrapping the entire function.
Yes, the item has a date that is a Ruby Date
puts Benchmark.measure {
grouped_items
}
def grouped_items
unless @grouped
@grouped = {}
@items.each do |item|
key = item.date
if @grouped.has_key?(key)
@grouped[key] << item
else
@grouped[key] = [item]
end
end
end
@grouped
end
Thanks for any insight you care to share.
Edit #1: My first optimization. I was aiming for a slightly more succinct function and gained a .2 seconds reduction in time to process 100_000 items.
def grouped_items
unless @grouped
@grouped = Hash.new { |h, k| h[k] = [] }
@items.map {|item| @grouped[item.date] << item }
end
@grouped
end
Edit #2: My second iteration with more or less the same performance profile but with much less code.
def grouped_items
@grouped ||= @items.group_by { |item| item.date }
end
Edit #3: An alternative way to do the same thing above.
def grouped_items
@grouped ||= @items.group_by &:date
end
-
\$\begingroup\$ Nope. I'll check that out. \$\endgroup\$rmontgomery429– rmontgomery4292012年07月07日 01:21:09 +00:00Commented Jul 7, 2012 at 1:21
-
\$\begingroup\$ In future can you flag for a mod to migrate, please don't cross-post. Thanks. \$\endgroup\$Kev– Kev2012年07月08日 00:58:49 +00:00Commented Jul 8, 2012 at 0:58
-
\$\begingroup\$ Did you try profiling the code? \$\endgroup\$Andrew Grimm– Andrew Grimm2012年07月12日 02:41:06 +00:00Commented Jul 12, 2012 at 2:41
2 Answers 2
Are you aware of Enumerable#group_by
?
def grouped_items
@items.group_by{|item| item.date}
end
-
\$\begingroup\$ It more or less performs the same as the first edit (see above) but with much less code. \$\endgroup\$rmontgomery429– rmontgomery4292012年07月07日 01:44:16 +00:00Commented Jul 7, 2012 at 1:44
-
1\$\begingroup\$ I just came back across this and wanted to comment again how awesome this solution is. :) \$\endgroup\$rmontgomery429– rmontgomery4292012年07月29日 17:44:05 +00:00Commented Jul 29, 2012 at 17:44
-
\$\begingroup\$ Just to add, you could even use symbol-to-proc here since you are grouping by an immediate method call:
@items.group_by &:date
. \$\endgroup\$Aaron Cronin– Aaron Cronin2014年12月16日 09:39:14 +00:00Commented Dec 16, 2014 at 9:39 -
\$\begingroup\$ Indeed, as the OP discovered and showed in his Edit #3. \$\endgroup\$Mark Thomas– Mark Thomas2014年12月16日 14:24:32 +00:00Commented Dec 16, 2014 at 14:24
What about this?
@items.group_by { |item| item.effective_date }
Benchmarks for the curious:
Ryan v1 : 1.080000 0.000000 1.080000 ( 1.077599)
Ryan v2 : 0.620000 0.000000 0.620000 ( 0.622756)
group_by: 0.580000 0.000000 0.580000 ( 0.576531)