patternrubyMinor
Subtraction accumulator
Viewed 0 times
subtractionaccumulatorstackoverflow
Problem
I'm currently following the tutorials over at RubyMonk, and one of the problems I need to solve is to write a
Coming from a traditional imperative programming background (C, Lua, Java, etc.), my first attempt would have been something like this:
But, this just felt wrong in Ruby, and I don't doubt that it is. Trying to use a more Ruby-esque style, I thought it would be better to use some of
Here is my latest version:
One thing to note is that this is essentially the same thing as above, I just moved most of the looping into
Therefore my questions are:
subtract function that would meet these conditions:- invoking
subtract(4, 5)should return-1
- invoking
subtract(-10, 2, 3)should return-15
- invoking
subtract(0, 0, 0, 0, -10)should return10
Coming from a traditional imperative programming background (C, Lua, Java, etc.), my first attempt would have been something like this:
def subtract *numbers
start = numbers[0]
tail = numbers.drop(1)
for i in tail do
start -= i
end
return start
endBut, this just felt wrong in Ruby, and I don't doubt that it is. Trying to use a more Ruby-esque style, I thought it would be better to use some of
Array's methods.Here is my latest version:
def subtract *numbers
(numbers.drop 1).inject(numbers[0]) { |x, y| x-y}
endOne thing to note is that this is essentially the same thing as above, I just moved most of the looping into
Array#inject. To me, simply moving logic isn't a new style per se, and so conceptually this is nothing new to me.Therefore my questions are:
- Is this true Ruby style? If not, how could I make it so, and how would that new style differ from the current?
- Is there any way to improve readability? ('Cause honestly the current version lacks quite a bit).
Solution
Some notes:
-
-
-
As @Nakilon pointed out, you can drop the
-
The identity value for subtraction is
-
We can now write:
For me, simply moving logic isn't a new style per se, and so conceptually this is nothing new to me.
I don't agree. The steps followed are conceptually the same, yes, but the use of a widely known generic abstraction like
-
def subtract *numbers: While Ruby allows to omit parens, the community consensus is that it makes signatures harder to read. -
(numbers.drop 1): When you have to write parens like this, it's a signal that you should just write them in the method call. It looks like Scala or Haskell, not Ruby.-
As @Nakilon pointed out, you can drop the
drop/first, a fold without an initial value takes the first one.-
The identity value for subtraction is
0, let's use it for empty inputs.-
xs.inject(initial) { |acc, x| acc.method(x) } -> xs.inject(initial, :method)We can now write:
def subtract(*numbers)
numbers.inject(0, :-)
endFor me, simply moving logic isn't a new style per se, and so conceptually this is nothing new to me.
I don't agree. The steps followed are conceptually the same, yes, but the use of a widely known generic abstraction like
reduce/inject has reduced the overall complexity. Of course, one abstraction does not make much difference, but dozens of them change the way a whole program describes what it's doing. And that's what programing is about: building abstractions to reduce complexity.Code Snippets
def subtract(*numbers)
numbers.inject(0, :-)
endContext
StackExchange Code Review Q#25394, answer score: 4
Revisions (0)
No revisions yet.