[Ruby] [Physical Gymnastics] Enumeration and Calculation of Reverse Polish Notation

less than 1 minute read

Enumeration

Enumerate all patterns by arithmetic operations when given [1, 2, 3, 4]

require "set"
NUMBERS = [1, 2, 3, 4]
SIGNS = %i[+-/ *]

results =
  NUMBERS.permutation(4).uniq.each.with_object(Set.new) do |numbers, results|
    (SIGNS * 3).permutation(3).uniq.each do |signs|
      a, b, c, d = numbers
      x, y, z = signs

      [c, d, x, y].permutation(4).uniq.each do |combination|
        next if combination.join.match(/\A([^\d]{2})/)

        results << ([a, b, *combination, z]).join(" ")
      end
    end
  end

# results.size => 7680

The calculation

Given 1 2 3 4 +-/, returns -0.2

require'active_support/core_ext/object/blank'

class Rpn
  SIGNS = %i[+-/ *]

  class << self
    def calc(rpn_text)
      rpn = new(rpn_text)
      rpn.calc
    end
  end

  def initialize(rpn_text)
    @stack = notation_to_a(rpn_text)
  end

  def calc(this_stack = stack)
    return this_stack.first if this_stack.size == 1

    operator_at = this_stack.index{|x| SIGNS.include? x}
    operator = this_stack[operator_at]
    value = this_stack[operator_at-2].send(operator, this_stack[operator_at-1])
    this_stack[(operator_at-2)..operator_at] = value

    return calc(this_stack)
  end

  private

  attr_reader :stack

  def notation_to_a(rpn_text)
    rpn_text.chars.select(&:present?).collect do |x|
      SIGNS.include?(x.to_sym) ?x.to_sym :x.to_f
    end
  end
end

Rpn.calc("1 2 3 4 +-/") # => -0.2