Better way of comparing integers I wrote this class which is comparing some values, how can I improve its performance and maybe make it prettier?

You can see at the bottom what type of data it requires, also the array size can reach 100 000 elements.

As it is the class is working fine, but I would like to get a second opinion on how to improve it (I know that is not something complicated but I would like to find new ways of doing this).

module Stat
  class CompareData
    def initialize(datas)
      @datas = datas
      @result_data = {'g_yesterday' =&gt; {inc: 0, dec: 0}, 'g_week' =&gt; {inc: 0, dec: 0}, 'g_month' =&gt; {inc: 0, dec: 0}}
end

  def get_data
    @datas.each do |data|
      %w[g_yesterday g_week g_month].each do |compare|
        @today_value = data.g_current
        compare_data data[compare], compare
      end
    end
    @result_data
  end

  private
  def compare_data second_value, date
    unless @today_value == 0 &amp;&amp; second_value == 0
      if @today_value != second_value
        period = @result_data[date]
        period[:dec] += 1 if @today_value == 0
        if second_value == 0
          period[:inc] += 1
        else
          @today_value &lt; second_value ? period[:inc] += 1 : period[:dec] += 1
        end
      end
    end
  end
 end
end

values = [{'g_current' =&gt; '2', 'g_yesterday' =&gt; '0', 'g_week' =&gt; '3', 'g_month' =&gt; '4'}, ..]

init = Stat::CompareData.new(values)
init.get_data


EDIT

I have pasted the wrong code here is the one that I wanted to post:

  def get_data
    @datas.each do |data|
      %w[g_yesterday g_week g_month].each do |compare|
        @today_value = data['g_current'].to_i
        compare_data data[compare].to_i, compare
      end
    end
    @result_data
  end

  def compare_data second_value, date
    unless @today_value == 0 &amp;&amp; second_value == 0
      if @today_value != second_value
        period = @result_data[date]
        if @today_value == 0 || second_value == 0
          @today_value &gt; second_value ? period[:inc] += 1 : period[:dec] += 1
        else
          @today_value &gt; second_value ? period[:dec] += 1 : period[:inc] += 1
        end
      end
    end
  end
I'm not usually harsh, but this code is a buggy mess. Sorry.

We don't review broken code on CodeReview, but I just can't help myself. As I said in a comment, this code is so broken that it actually ends up almost working correctly.

Well, except for the fact that data.g_current raises an exception, because you should be writing data['g_current'].

But let's ignore that and look at #compare_data:

def compare_data second_value, date
  # this is *always* false, since neither value is a number;
  # they're strings and a string can't be zero
  unless @today_value == 0 &amp;&amp; second_value == 0

    # And this condition makes the one above completely redundant anyway
    if @today_value != second_value
      period = @result_data[date]

      # This *never* happens because (again) a string can't be zero.
      # But that's a good thing, because if it worked, and
      # @today_value was zero, while second_value was 1 or more
      # you'd end up adding 1 to :dec here, *and* adding 1 to
      # :inc in the else-block below
      period[:dec] += 1 if @today_value == 0

      if second_value == 0
        # this never happens either (same reason again)
        period[:inc] += 1
      else

        # this is the only line that'll ever actually do anything!
        # ... but it's broken.
        # You're comparing strings, not numbers, so in string terms,
        # "2" is greater than "10", "323" is less than "5" and so on,
        # and the branch will do the wrong thing. It just happens to
        # work if both values are single digit strings
        @today_value &lt; second_value ? period[:inc] += 1 : period[:dec] += 1
      end
    end
  end
end


In other words: there are issues here.

Other stuff:


What you want is a method, not a class. What you seem to be going for is a straight folding/reduction of a data set (i.e. Array#inject).
You're setting an instance variable in a loop (@today_value), and relying on that in a method. This is, frankly, terrible. If anything, just pass it to the method as an argument. There's just a lot of really weird coupling and state-keeping going on, none of which should be happening.
#get_data should be idempotent. Right now, if you call it more than once, you'll just get larger and larger inc/dec values because you keep adding to the same @result_data hash. But again, you don't want a class anyway.
And #get_data is stranger still. You set @today_value again and again although it doesn't change in the inner each loop.
Fix your indentation
Don't call a class CompareData. Classes should be nouns; "compare data" is imperative. And don't call a variable init, and don't pluralize data since it's already plural.
Be consistent with your parentheses. You use them for #initialize, but you don't for #compare_data


Here's something that I think is closer to what you're actually trying to do

changes = values.inject({'g_yesterday' =&gt; {inc: 0, dec: 0}, 'g_week' =&gt; {inc: 0, dec: 0}, 'g_month' =&gt; {inc: 0, dec: 0}}) do |memo, datum|
  current = datum['g_current'].to_i
  memo.each do |key, hash|
    previous = datum[key].to_i
    if current &lt; previous
      hash[:inc] += 1
    elsif current &gt; previous
      hash[:dec] += 1
    end
  end
  memo
end


No class, no strange coupling or state-keeping. Just input and output.



Update: New code posted, and while my answer was already accepted, I might as well. The new code is thankfully working with numbers rather than strings, which helps, but most of my points above still stand. Looking at the #compare_data method again:

def compare_data second_value, date
  # just return if you don't want to run the rest of the code
  unless @today_value == 0 &amp;&amp; second_value == 0

    # again: This condition makes the one above pointless
    # and again, just return instead of wrapping everything
    if @today_value != second_value
      period = @result_data[date]

      # Why are zeros treated differently? Isn't the point simply to figure
      # out what value is higher, and update inc/dec accordingly?
      # Why does one of the values being zero make it behave exactly
      # opposite of how it behaves if both values are non-zero?
      #
      #  today_value   |  second_value   |  Add 1 to...
      # ----------------------------------------------
      #  1  (highest)  |  0              |  :inc
      #  2  (highest)  |  1              |  :dec
      #
      # This doesn't make sense to me... 
      if @today_value == 0 || second_value == 0
        @today_value &gt; second_value ? period[:inc] += 1 : period[:dec] += 1
      else
        @today_value &gt; second_value ? period[:dec] += 1 : period[:inc] += 1
      end
    end
  end
end