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?
2 Answers 2
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
-
\$\begingroup\$ Pretty good. Btw, I think you don't need the 0 in
reduce(0, :+)
. \$\endgroup\$Alexander Popov– Alexander Popov2013年11月21日 10:38:42 +00:00Commented Nov 21, 2013 at 10:38 -
1\$\begingroup\$ @AlexPopov: Well, it's just to consider the case
f(x) = 0
. \$\endgroup\$tokland– tokland2013年11月21日 10:46:43 +00:00Commented Nov 21, 2013 at 10:46 -
\$\begingroup\$ Good point, didn't think about that. \$\endgroup\$Alexander Popov– Alexander Popov2013年11月21日 10:50:40 +00:00Commented Nov 21, 2013 at 10:50
-
\$\begingroup\$ Btw, if you have
zero = Polynomial.new 0
, the code throwsundefined method `reverse' for 0:Fixnum (NoMethodError)
. \$\endgroup\$Alexander Popov– Alexander Popov2013年11月21日 10:59:06 +00:00Commented 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– tokland2013年11月21日 14:40:46 +00:00Commented Nov 21, 2013 at 14:40
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
-
\$\begingroup\$ 10x, I had figured out the first version you proposed, but I didn't pass a
0
toreduce
as a starting parameter, so it was giving meno implicit conversion of Fixnum into Array
\$\endgroup\$Alexander Popov– Alexander Popov2013年11月21日 09:32:05 +00:00Commented 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\$Chandranshu– Chandranshu2013年11月21日 09:36:21 +00:00Commented Nov 21, 2013 at 9:36