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?

\$\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
\$\endgroup\$
7
  • \$\begingroup\$ Pretty good. Btw, I think you don't need the 0 in reduce(0, :+). \$\endgroup\$ Nov 21, 2013 at 10:38
  • 1
    \$\begingroup\$ @AlexPopov: Well, it's just to consider the case f(x) = 0. \$\endgroup\$
    – tokland
    Nov 21, 2013 at 10:46
  • \$\begingroup\$ Good point, didn't think about that. \$\endgroup\$ 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\$ 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\$
    – tokland
    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
\$\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\$ 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\$ Nov 21, 2013 at 9:36

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.