Skip to content

Instantly share code, notes, and snippets.

@litch
Last active December 20, 2015 01:29
Show Gist options
  • Save litch/6049233 to your computer and use it in GitHub Desktop.
Save litch/6049233 to your computer and use it in GitHub Desktop.
RPN 3 ways. I had two - then tried to do the pattern-matching solution, wound up being intermediate performance...
require 'rspec/autorun'
require 'benchmark'
describe "polish notation" do
it "do a trivial case" do
polish_parser(:+, 1, 1).first.should == 2
reverse_stack_polish_parser(:+, 1, 1).first.should == 2
pm_polish_parser(:+, 1, 1).first.should == 2
end
it "can do two things" do
polish_parser(:+, :-, 1, 1, 1).first.should == 1
reverse_stack_polish_parser(:+, :-, 1, 1, 1).first.should == 1
pm_polish_parser(:+, :-, 1, 1, 1).first.should == 1
end
it "can do something complex" do
polish_parser(:-, :*, :div, 15, :-, 7, :+, 1, 1, 3, :+, 2, :+, 1, 1).first.should == 5
reverse_stack_polish_parser(:-, :*, :div, 15, :-, 7, :+, 1, 1, 3, :+, 2, :+, 1, 1).first.should == 5
pm_polish_parser(:-, :*, :div, 15, :-, 7, :+, 1, 1, 3, :+, 2, :+, 1, 1).first.should == 5
end
it "is performant" do
Benchmark.bmbm do |results|
results.report("reverse_stack") { 100000.times { reverse_stack_polish_parser(:-, :*, :div, 15, :-, 7, :+, 1, 1, 3, :+, 2, :+, 1, 1) }}
results.report("recursive") { 100000.times { polish_parser(:-, :*, :div, 15, :-, 7, :+, 1, 1, 3, :+, 2, :+, 1, 1) }}
results.report("pattern matched") { 100000.times { pm_polish_parser(:-, :*, :div, 15, :-, 7, :+, 1, 1, 3, :+, 2, :+, 1, 1) }}
end
end
end
# Rehearsal ---------------------------------------------------
# reverse_stack 0.680000 0.110000 0.790000 ( 0.791758)
# recursive 3.210000 0.000000 3.210000 ( 3.212995)
# pattern matched 1.770000 0.010000 1.780000 ( 1.774518)
# ------------------------------------------ total: 5.780000sec
# user system total real
# reverse_stack 0.780000 0.420000 1.200000 ( 1.204618)
# recursive 3.230000 0.000000 3.230000 ( 3.235451)
# pattern matched 1.710000 0.000000 1.710000 ( 1.718585)
def pm_polish_parser(*args)
if args[0].is_a?(Symbol) && args[1].is_a?(Fixnum) && args[2].is_a?(Fixnum)
calc = args[1].send(args[0], args[2])
return calc, *args[3..-1]
elsif args[0].is_a?(Symbol) && args[1].is_a?(Fixnum) && args[2].is_a?(Symbol)
pm_polish_parser(args[0], args[1], *pm_polish_parser(*args[2..-1]))
else
pm_polish_parser args[0], *pm_polish_parser(*args[1..-1])
end
end
def reverse_stack_polish_parser(*args)
stack = []
args.reverse_each { |arg|
if !arg.is_a? Symbol
stack.push(arg)
else
operand1 = stack.pop
operand2 = stack.pop
stack.push operand1.send(arg, operand2)
end
}
stack
end
# RECURSIVE METHOD
def polish_parser(*args)
if result = match_and_operate(*args)
result
else
second_symbol_index = args[1..-1].find_index{|a| a.is_a? Symbol}
saved_args = args[0..second_symbol_index]
mutated_args = polish_parser(*args[second_symbol_index+1..-1])
result = polish_parser(*saved_args, *mutated_args)
end
end
def match_and_operate(*args)
if args[0].is_a?(Symbol) && args[1].is_a?(Fixnum) && args[2].is_a?(Fixnum)
calc = args[1].send(args[0], args[2])
return calc, *args[3..-1]
else
return false
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment