2

I'm new to ruby and was going though a piece of code

scope_value = {"tickets_scope"=>"1", "changes_scope"=>"8", "solutions_scope"=>"15"}
scope_value.values.map { |i| 2** i.to_i }.inject(0, :|)

I realised

scope_value.values.map {|i| 2** i.to_i }.sum

does the the same thing as well

In terms of functionality doesn't both lines of code do the same thing. Is there any advantage to using sum over the other in terms of performance.

thebenman
  • 1,621
  • 14
  • 35
  • 1
    `sum` was added in the version 2.4 of Ruby (Rails had it before), it was a common practice to use inject in that way. – Sebastián Palma Oct 08 '19 at 15:25
  • 1
    Readers know what `scope_value.values` means, and that you will need to convert the values of the hash to integers with `to_i`, so your question could be improved by simplifying it to its essence: `scope_values = [1, 8, 15]; scope_values.map...`. – Cary Swoveland Oct 08 '19 at 16:36

2 Answers2

5

In terms of functionality doesn't both lines of code do the same thing.

Yes, these two snippets produce identical results.

Does inject starting from 0 mean the same as sum

No, not at all. In fact, 0 is irrelevant here. You can omit it and still get the same result.

scope_value.values.map { |i| 2** i.to_i }.inject(:|)

Operations in these two snippets are very different. They only produce the same result because of special shape of your data. Which is "each number has only one bit set and no two numbers have the same bit set". Violate this rule and see results diverge.


BTW, before we had .sum, we used to emulate it with .inject(:+). This does the same thing (when used on integer arrays)

Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • 3
    @Sergio, you've been AWOL. Forgot not an edge case: `[].sum #=> 0; [].inject(:+) #=> nil`. We can say that `arr.sum` produces the same result as `arr.inject(0, :+)` so long as all elements of `arr` (if any) are numeric. – Cary Swoveland Oct 08 '19 at 16:27
  • @CarySwoveland: sorry about that. New job, new place, not so much time :) Thanks for clarification – Sergio Tulentsev Oct 08 '19 at 17:29
  • @thebenman: same what it does outside of inject. When used on integers, it means [bitwise OR](https://en.wikipedia.org/wiki/Bitwise_operation#OR): https://ruby-doc.org/core-2.5.0/Integer.html#method-i-7C But as far as ruby is concerned, it's just a method. On arrays it means something else completely, for example. – Sergio Tulentsev Oct 08 '19 at 17:31
  • 1
    @Sergio, non-numeric elements that respond to `:+` can be summed as well if `sum` is given its optional argument, an initial value. The doc [Array#sum](https://ruby-doc.org/core-2.6.3/Array.html#method-i-sum) gives the example `["a", "b", "c"].sum("") #=> "abc"`. New city? New country? – Cary Swoveland Oct 08 '19 at 17:34
1

They do mean the same thing, but only because you don't use Floats and only because you don't have a Range.

At least in some versions of some Ruby implementations, sum has some optimizations and specializations that inject and + can't have because they are much more general. For example, in YARV, the current implementation of the various variations of sum is almost 200 lines, and includes the following optimizations

The price we pay for this is that sum may ignore monkeypatched versions of each or +.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653