0

I'm trying to write a method called calculate which determine to add or subtract numbers depending on a keyword argument passed to it.

Here're the methods:

def add(*num)
  num.inject(:+)
end

def subtract(*num)
  num.reduce(:-)
end

def calculate(*num, **op)
  return add(num) if op[:add] || op.empty?
  return subtract(num) if op[:subtract]
end

puts calculate(1, 2, 3, add: true)
puts calculate(1, 2, 3, subtract: true)

When I run this function, I get this result:

1
2
3

1
2
3
Rafael Adel
  • 7,673
  • 25
  • 77
  • 118
  • @sawa Is it done using splat only and extracting the last element ? Sorry I'm quite new to Ruby – Rafael Adel Feb 21 '15 at 20:25
  • 1
    If you follow my advise, then your method will be simply `def calculate *args, op; args.inject(case op; when :add then :+; when :subtract then :- end) end`. – sawa Feb 21 '15 at 20:26
  • 1
    Or, if you decide you can go with `calculate(1, 2, 3, :+)`, `calculate(1, 2, 3, :-)`, then it would be `def calculate *args, op; args.inject(op) end`. – sawa Feb 21 '15 at 20:28

2 Answers2

2

puts is your friend:

def add(*num)
  puts "in add, num = #{num}, num.size = #{num.size}"
  num.inject(:+)
end

def calculate(*num, **op)
  puts "num = #{num}, op = #{op}"
  return add(num) if op[:add] || op.empty?
end

calculate(1, 2, 3, add: true)
  # num = [1, 2, 3], op = {:add=>true}
  # in add, num = [[1, 2, 3]], num.size = 1
  #=> nil

Now fix calculate:

def calculate(*num, **op)
  puts "num = #{num}, op = #{op}"
  return add(*num) if op[:add] || op.empty?
end

calculate(1, 2, 3, add: true)
  # num = [1, 2, 3], op = {:add=>true}
  # in add, num = [1, 2, 3], num.size = 3
  # => 6 
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
  • But can you tell me why in `calculate` method body, replacing `add(num)` with `add(*num)` solved it ? – Rafael Adel Feb 21 '15 at 21:18
  • Say `a = [1,2,3]`. `add` adds its arguments together, so : `add(*a) => add(1,2,3) => 6`. With `add(a)`, `add` has only one argument, the array `a`. When one or more arrays are passed as arguments to `add`, `arr.inject(:+)` uses [Array#+](http://ruby-doc.org//core-2.2.0/Array.html#method-i-2B), not [Fixnum#+](http://ruby-doc.org//core-2.2.0/Fixnum.html#method-i-2B): `add([1,2],[3,4]) => [1, 2, 3, 4] `, `add([1,2]) => [1, 2] `. Got it? – Cary Swoveland Feb 21 '15 at 21:44
0

You write :

return add(*num) if opt[:add] || opt.empty?

Same way modify the return subtract.. Part too.

With your posted code num becomes [[1,2,3]], and thus [[1,2,3]].inject(:+) gives return the receiver back. And you called puts on it, so it outputs like as you got.

Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317