5
\$\begingroup\$

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
\$\endgroup\$
3
  • \$\begingroup\$ Nope. I'll check that out. \$\endgroup\$ 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
    Jul 8, 2012 at 0:58
  • \$\begingroup\$ Did you try profiling the code? \$\endgroup\$ Jul 12, 2012 at 2:41

2 Answers 2

8
\$\begingroup\$

Are you aware of Enumerable#group_by?

def grouped_items
  @items.group_by{|item| item.date}
end
\$\endgroup\$
4
  • \$\begingroup\$ It more or less performs the same as the first edit (see above) but with much less code. \$\endgroup\$ 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\$ 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\$ Dec 16, 2014 at 9:39
  • \$\begingroup\$ Indeed, as the OP discovered and showed in his Edit #3. \$\endgroup\$ Dec 16, 2014 at 14:24
4
\$\begingroup\$

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)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.