Search code examples
rubyarrayssum

In Ruby, how do I get the sum of the odd elements?


I have an array like:

["4|23", "1", "3|10", "2"]

I want to get the sum of the odd elements, i.e. 1 + 2 = 3, perhaps with inject?

This is the response by Redis ZRANGE WITHSCORES for a sorted set. Ideally, I want to get the sum of the SCORES in a sorted set.


Solution

  • Thanks to everyone for your answers. All of them were really cool & enlightening.

    I came up with an answer of my own. It's pretty straightforward:

    sum = 0; gifts.each_with_index { |s, i| sum += s.to_i if i % 2 == 1 }; sum
    

    I did a performance check:

    require "benchmark"
    MANY = 50000    
    gifts = [
      "4|2323", "1",
      "3|102343", "2",
      "0|12330", "1",
      "3|10234873", "2",
      "5|2343225", "1",
      "5|23423744", "1",
      "2|987", "4",
      "0|987345", "1",
      "2|46593", "1",
      "4|78574839", "3",
      "3|4756848578", "1",
      "3|273483", "3"
    ]
    
    Benchmark.bmbm do |x|
      x.report("each_with_index") { MANY.times { sum = 0; gifts.each_with_index { |s, i| sum += s.to_i if i % 2 == 1 }; sum } }
      x.report("each_with_index") { MANY.times { sum = 0; gifts.each_with_index { |s, i| sum += s.to_i if i.odd? }; sum } }
      x.report("values_at") { MANY.times { gifts.values_at(*(1..gifts.length).step(2)).inject(0) { |s, n| s += n.to_i } } }
      x.report("each_slice") { MANY.times { gifts.each_slice(2).inject(0) { |i, (j,k)| i += k.to_i } } }
      x.report("values_at") { MANY.times { gifts.values_at(*gifts.each_index.select { |i| i.odd? }).map(&:to_i).inject(&:+) } }
      x.report("hash") { MANY.times { Hash[*gifts].values.map(&:to_i).reduce(:+) } }
    end
    

    Running the script above output the following on my Mac:

                          user     system      total        real
    each_with_index   0.300000   0.000000   0.300000 (  0.305377)
    each_with_index   0.340000   0.000000   0.340000 (  0.334806)
    values_at         0.370000   0.000000   0.370000 (  0.371520)
    each_slice        0.380000   0.000000   0.380000 (  0.376020)
    values_at         0.540000   0.000000   0.540000 (  0.539633)
    hash              0.560000   0.000000   0.560000 (  0.560519)
    

    Looks like my answer is the fastest. :-)