Ruby mathematical formula from string with 'x'

Viewed 563

In order not to get rusty I want to refresh my knowledge of pure ruby by solving some algorithms. I can't solve a larger algorithm without solving a smaller one like the example below.

Have the function missing_digit(str) take the str parameter, which will be a simple mathematical formula with three numbers, a single operator (+, -, *, or /) and an equal sign (=) and return the digit that completes the equation. In one of the numbers in the equation, there will be an x character, and your program should determine what digit is missing. For example, if str is "3x + 12 = 46" then your program should output 4.

Examples
Input: "4 - 2 = x"
Output: 2
Input: "1x0 * 12 = 1200"
Output: 0

I think I found the solution for python but I can't find the corresponding Ruby code anywhere.

2 Answers

Python and Ruby are quite similar, though trying to convert this without some basic TDD would have been difficult. Here is the converted to Ruby file from your python example. I would refactor this code but the simple tests here pass, those given in your linked example.

string_math_x.rb

class StringMathX
  def self.calculate(str)
    exp = str.split()

    first_operand = exp[0]
    operator = exp[1]
    second_operand = exp[2]
    resultant = exp[-1]

    # If x is present in resultant
    if resultant[/x/]
      first_operand = first_operand.to_i
      second_operand = second_operand.to_i

      if operator == '+'
        res = first_operand + second_operand
      elsif operator == '-'
        res = first_operand - second_operand
      elsif operator == '*'
        res = first_operand * second_operand
      else
        res = first_operand / second_operand
      end
      return res
    end

    # If x in present in operands

    # If x in the first operand
    if first_operand == 'x'
      x = first_operand.to_i
      second_operand = second_operand.to_i

      if operator == '+'
        res = resultant - second_operand
      elsif operator == '-'
        res = resultant + second_operand
      elsif operator == '*'
        res = resultant / second_operand
      else
        res = resultant / second_operand
      end
    # If x is in the second operand
    else
      x = second_operand.to_i
      first_operand = first_operand.to_i
      if operator == '+'
        res = resultant-first_operand
      elsif operator == '-'
        res = first_operand - second_operand
      elsif operator == '*'
        res = resultant.to_i / first_operand.to_i
      else
        res = first_operand.to_i / resultant.to_i
      end
    end
    res = res.to_s
    k = 0
    for i in [*0..x]
      if i == x
        result = res[k]
        break
      else
        k += 1
      end
    end
    result.to_i
  end
end

./test/test.rb

require 'minitest/autorun'
require_relative '../lib/string_math_x'
class StringMathXTest < Minitest::Test
  def test_basic_subtration
    input = '4 - 2 = x'
    assert(StringMathX.calculate(input) == 2, 'outputs 2')
  end
  def test_whats_up_returns_doc
    input = '1x0 * 12 = 1200'
    assert(StringMathX.calculate(input) == 0, 'outputs 0')
  end
end

To run this you may need to gem install minitest

Then run ruby test/test.rb

def findx(str)
  s = str.sub('=', '==')
  i = s.index('x')
  pre = s[0,i]
  post = s[i+1..-1]
  ('0'..'9').find { |d| eval(pre+d+post) rescue nil }&.to_i
end
findx("4 - 2 = x")        #=> 2
findx("1x0 * 12 = 1200")  #=> 0
findx("3**x = 81")        #=> 4
findx("1/x == 2.0").nil?  #=> true

rescue nil is needed in case division by zero is performed. & is the safe harbor operator. It returns nil, disregarding all that follows, if the part before it returns nil.

Related