3
\$\begingroup\$

I've written a small function for solving simple quadratic equations:

class EquationSolver
 def solve(x, *args)
 args.reverse.map.with_index { |coefficient, index| coefficient * x ** index }.reduce { |result, element| result + element }
 end
end

To calculate f(3) for f(x)=3x3−2x2−x+5, one would write:

puts EquationSolver.new.solve(3, 3, -2, -1, 5)

However, is there a more elegant version of my function, more like reduce.with_index or something similar?

asked Nov 21, 2013 at 7:47
\$\endgroup\$
0

2 Answers 2

2
\$\begingroup\$

Some notes:

  • If you use a OOP approach, it seems more logical to use methods.
  • Use arrays to group values that go together.
  • I don't think solve is the correct term, that's when you are finding the roots of a function, here you're just evaluating it at a given point.

I'd write:

class Polynomial
 attr_accessor :coefficients 
 def initialize(coefficients)
 self.coefficients = coefficients.reverse
 end
 def evaluate(x)
 coefficients.map.with_index { |k, power| k * (x**power) }.reduce(0, :+)
 end
end
polynomial = Polynomial.new([3, -2, -1, 5])
puts polynomial.evaluate(3) #=> 65
answered Nov 21, 2013 at 10:35
\$\endgroup\$
7
  • \$\begingroup\$ Pretty good. Btw, I think you don't need the 0 in reduce(0, :+). \$\endgroup\$ Commented Nov 21, 2013 at 10:38
  • 1
    \$\begingroup\$ @AlexPopov: Well, it's just to consider the case f(x) = 0. \$\endgroup\$ Commented Nov 21, 2013 at 10:46
  • \$\begingroup\$ Good point, didn't think about that. \$\endgroup\$ Commented Nov 21, 2013 at 10:50
  • \$\begingroup\$ Btw, if you have zero = Polynomial.new 0, the code throws undefined method `reverse' for 0:Fixnum (NoMethodError). \$\endgroup\$ Commented Nov 21, 2013 at 10:59
  • 1
    \$\begingroup\$ @Alex: Yes. Personally I don't like this because it makes difficult to add extra arguments. IMHO the coefficients should be grouped, and an array is the most obvious way to do it. \$\endgroup\$ Commented Nov 21, 2013 at 14:40
2
\$\begingroup\$

Yes, there is a more elegant version. Here it is:

class EquationSolver
 def solve(x, *args)
 args.reverse.each_with_index.reduce(0) { |result, (coefficient, index)| result + coefficient * x ** index }
 end
end

It's possible to do this because iterator methods like each_with_index, when called without a block, return an Enumerator object on which you can call all the methods of the Enumerable.

In fact, an even shorter solution is obtained by using a variation of reduce to use a symbolic operator:

class EquationSolver
 def solve(x, *args)
 args.reverse.map.with_index { |coefficient, index| coefficient * x ** index }.inject(:+)
 end
end
answered Nov 21, 2013 at 8:45
\$\endgroup\$
2
  • \$\begingroup\$ 10x, I had figured out the first version you proposed, but I didn't pass a 0 to reduce as a starting parameter, so it was giving me no implicit conversion of Fixnum into Array \$\endgroup\$ Commented Nov 21, 2013 at 9:32
  • \$\begingroup\$ Yep, it tends to happen. I'd any day prefer my second variation since it makes for an easy reading. \$\endgroup\$ Commented Nov 21, 2013 at 9:36

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.