[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

[QUIZ] Postfix to Infix (#148

James Gray

11/30/2007 1:28:00 PM

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rub...

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone
on Ruby Talk follow the discussion. Please reply to the original quiz message,
if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

There are many different ways to write mathematical equations. Infix notation
is probably the most popular and yields expressions like:

2 * (3 + 5)

Some people like to work with a postfix notation (often called Reverse Polish
Notation or just RPN) though, which doesn't require parentheses for the same
equation:

2 3 5 + *

You can compare the results of these equations using the Unix utilities bc
(infix) and dc (postfix):

$ bc <<< '2 * (3 + 5)'
16
$ dc <<< '2 3 5 + * p'
16

The "p" instruction tacked onto the end of the expression for dc just tells it
to print the result.

This week's quiz is to write a script that translates postfix expressions into
the equivalent infix expression. In the simplest form, your script should
function as such:

$ ruby postfix_to_infix.rb '2 3 +'
2 + 3

At minimum, try to support the four basic math operators: +, -, *, and /. Feel
free to add others though. For numbers, remember to accept decimal values.

You can count on the postfix expressions having spaces between each term, if you
like. While dc is content with 2 3+p, you don't have to support it unless you
want to.

For an added bonus, try to keep the parentheses added to infix expressions to
the minimum of what is needed. For example, prefer these results:

$ ruby postfix_to_infix.rb '56 34 213.7 + * 678 -'
56 * (34 + 213.7) - 678
$ ruby postfix_to_infix.rb '1 56 35 + 16 9 - / +'
1 + (56 + 35) / (16 - 9)

to these:

$ ruby postfix_to_infix.rb '56 34 213.7 + * 678 -'
((56 * (34 + 213.7)) - 678)
$ ruby postfix_to_infix.rb '1 56 35 + 16 9 - / +'
(1 + ((56 + 35) / (16 - 9)))

Posting equations and your output is not a spoiler.

45 Answers

Christian von Kleist

11/30/2007 3:24:00 PM

0

On Nov 30, 2007 8:28 AM, Ruby Quiz <james@grayproductions.net> wrote:
> The three rules of Ruby Quiz:
>
> 1. Please do not post any solutions or spoiler discussion for this quiz until
> 48 hours have passed from the time on this message.
>
> 2. Support Ruby Quiz by submitting ideas as often as you can:
>
> http://www.rub...
>
> 3. Enjoy!
>
> Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone
> on Ruby Talk follow the discussion. Please reply to the original quiz message,
> if you can.
>
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
>
> There are many different ways to write mathematical equations. Infix notation
> is probably the most popular and yields expressions like:
>
> 2 * (3 + 5)
>
> Some people like to work with a postfix notation (often called Reverse Polish
> Notation or just RPN) though, which doesn't require parentheses for the same
> equation:
>
> 2 3 5 + *
>
> You can compare the results of these equations using the Unix utilities bc
> (infix) and dc (postfix):
>
> $ bc <<< '2 * (3 + 5)'
> 16
> $ dc <<< '2 3 5 + * p'
> 16
>
> The "p" instruction tacked onto the end of the expression for dc just tells it
> to print the result.
>
> This week's quiz is to write a script that translates postfix expressions into
> the equivalent infix expression. In the simplest form, your script should
> function as such:
>
> $ ruby postfix_to_infix.rb '2 3 +'
> 2 + 3
>
> At minimum, try to support the four basic math operators: +, -, *, and /. Feel
> free to add others though. For numbers, remember to accept decimal values.
>
> You can count on the postfix expressions having spaces between each term, if you
> like. While dc is content with 2 3+p, you don't have to support it unless you
> want to.
>
> For an added bonus, try to keep the parentheses added to infix expressions to
> the minimum of what is needed. For example, prefer these results:
>
> $ ruby postfix_to_infix.rb '56 34 213.7 + * 678 -'
> 56 * (34 + 213.7) - 678
> $ ruby postfix_to_infix.rb '1 56 35 + 16 9 - / +'
> 1 + (56 + 35) / (16 - 9)
>
> to these:
>
> $ ruby postfix_to_infix.rb '56 34 213.7 + * 678 -'
> ((56 * (34 + 213.7)) - 678)
> $ ruby postfix_to_infix.rb '1 56 35 + 16 9 - / +'
> (1 + ((56 + 35) / (16 - 9)))
>
> Posting equations and your output is not a spoiler.
>
>

I had this as an assignment for a class once, in Java, so I'll sit
this one out. Fun quiz!

Robert Dober

11/30/2007 7:51:00 PM

0

On Nov 30, 2007 4:24 PM, Christian von Kleist <cvonkleist@gmail.com> wrote:
>
> On Nov 30, 2007 8:28 AM, Ruby Quiz <james@grayproductions.net> wrote:
> > The three rules of Ruby Quiz:
> >
> > 1. Please do not post any solutions or spoiler discussion for this quiz until
> > 48 hours have passed from the time on this message.
> >
> > 2. Support Ruby Quiz by submitting ideas as often as you can:
> >
> > http://www.rub...
> >
> > 3. Enjoy!
> >
> > Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone
> > on Ruby Talk follow the discussion. Please reply to the original quiz message,
> > if you can.
> >
> > -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
> >
> > There are many different ways to write mathematical equations. Infix notation
> > is probably the most popular and yields expressions like:
> >
> > 2 * (3 + 5)
> >
> > Some people like to work with a postfix notation (often called Reverse Polish
> > Notation or just RPN) though, which doesn't require parentheses for the same
> > equation:
> >
> > 2 3 5 + *
> >
> > You can compare the results of these equations using the Unix utilities bc
> > (infix) and dc (postfix):
> >
> > $ bc <<< '2 * (3 + 5)'
> > 16
> > $ dc <<< '2 3 5 + * p'
> > 16
> >
> > The "p" instruction tacked onto the end of the expression for dc just tells it
> > to print the result.
> >
> > This week's quiz is to write a script that translates postfix expressions into
> > the equivalent infix expression. In the simplest form, your script should
> > function as such:
> >
> > $ ruby postfix_to_infix.rb '2 3 +'
> > 2 + 3
> >
> > At minimum, try to support the four basic math operators: +, -, *, and /. Feel
> > free to add others though. For numbers, remember to accept decimal values.
> >
> > You can count on the postfix expressions having spaces between each term, if you
> > like. While dc is content with 2 3+p, you don't have to support it unless you
> > want to.
> >
> > For an added bonus, try to keep the parentheses added to infix expressions to
> > the minimum of what is needed. For example, prefer these results:
> >
> > $ ruby postfix_to_infix.rb '56 34 213.7 + * 678 -'
> > 56 * (34 + 213.7) - 678
> > $ ruby postfix_to_infix.rb '1 56 35 + 16 9 - / +'
> > 1 + (56 + 35) / (16 - 9)
> >
> > to these:
> >
> > $ ruby postfix_to_infix.rb '56 34 213.7 + * 678 -'
> > ((56 * (34 + 213.7)) - 678)
> > $ ruby postfix_to_infix.rb '1 56 35 + 16 9 - / +'
> > (1 + ((56 + 35) / (16 - 9)))
> >
> > Posting equations and your output is not a spoiler.
> >
> >
>
> I had this as an assignment for a class once, in Java, so I'll sit
> this one out. Fun quiz!
Why? I'd rather say that it is quite challange to provide a solution
in Ruby that is not just a rewrite of your Java solution.
I do not think that there are an "ethic" considerations ;).
Cheers
Robert



--

http://ruby-smalltalk.blo...

---
All truth passes through three stages. First, it is ridiculed. Second,
it is violently opposed. Third, it is accepted as being self-evident.
Schopenhauer (attr.)

Daniel Martin

12/1/2007 10:19:00 PM

0

"Christian von Kleist" <cvonkleist@gmail.com> writes:

> I had this as an assignment for a class once, in Java, so I'll sit
> this one out. Fun quiz!

Well, doubtless in java you solved it in a way that demonstrated your
use of certain basic data structures that you'd just learned about.

There are at least two completely different algorithms to use in
solving this in a conventional manner, and I've just solved it in a
third, completely unconventional ("evil") manner. So solve it in a
manner different from what you did in class.

(The no-spoiler rule makes phrasing this reply difficult)

Also, being strict about the minimal parentheses rule makes things a
bit interesting:

'1 2 + 3 4 + +' should become '1 + 2 + 3 + 4'

But:

'1 2 - 3 4 - -' should become '1 - 2 - (3 - 4)'

Likewise for multiplication and division.

Also, you could add exponentiation, but if you do remember that infix
exponentiation associates to the right, not the left, so:

'2 2 ^ 2 ^' should become '(2 ^ 2) ^ 2'

But:

'2 2 2 ^ ^' should become '2 ^ 2 ^ 2'

So really, there's lots more to it than whatever you did it in that
java class.

--
s=%q( Daniel Martin -- martin@snowplow.org
puts "s=%q(#{s})",s.to_a.last )
puts "s=%q(#{s})",s.to_a.last

Todd Benson

12/1/2007 10:28:00 PM

0

On Dec 1, 2007 4:18 PM, Daniel Martin <martin@snowplow.org> wrote:
> "Christian von Kleist" <cvonkleist@gmail.com> writes:
> But:
>
> '1 2 - 3 4 - -' should become '1 - 2 - (3 - 4)'

Or '1 - 2 - 3 + 4' (yikes!) :^0

Todd

Eric I.

12/1/2007 11:02:00 PM

0

On Dec 1, 5:27 pm, Todd Benson <caduce...@gmail.com> wrote:
> On Dec 1, 2007 4:18 PM, Daniel Martin <mar...@snowplow.org> wrote:
>
> > "Christian von Kleist" <cvonkle...@gmail.com> writes:
> > But:
>
> > '1 2 - 3 4 - -' should become '1 - 2 - (3 - 4)'
>
> Or '1 - 2 - 3 + 4' (yikes!) :^0

Well one feature of the Ruby Quiz is that our Quiz Master generally
allows submitters quite a bit of flexibility in reinterpreting the
problem. To me, however, that form seems outside the problem
description, as you're a) applying the distributive property, and b)
ending up with a different set of operators than what you started with
(from 3 minuses to 2 minuses and 1 plus).

And once you start down the road '4 2 3 + *' could become '4 * (2 +
3)', '8 + 12', or even '20'.

Eric

====

Are you interested in on-site Ruby training that's been highly
reviewed by former students? http://Lea...

Todd Benson

12/1/2007 11:31:00 PM

0

On Dec 1, 2007 5:05 PM, Eric I. <rubytraining@gmail.com> wrote:
> On Dec 1, 5:27 pm, Todd Benson <caduce...@gmail.com> wrote:
> > On Dec 1, 2007 4:18 PM, Daniel Martin <mar...@snowplow.org> wrote:
> >
> > > "Christian von Kleist" <cvonkle...@gmail.com> writes:
> > > But:
> >
> > > '1 2 - 3 4 - -' should become '1 - 2 - (3 - 4)'
> >
> > Or '1 - 2 - 3 + 4' (yikes!) :^0
>
> Well one feature of the Ruby Quiz is that our Quiz Master generally
> allows submitters quite a bit of flexibility in reinterpreting the
> problem. To me, however, that form seems outside the problem
> description, as you're a) applying the distributive property, and b)
> ending up with a different set of operators than what you started with
> (from 3 minuses to 2 minuses and 1 plus).
>
> And once you start down the road '4 2 3 + *' could become '4 * (2 +
> 3)', '8 + 12', or even '20'.
>
> Eric

Of course. It's not a quiz about simplification. I just thought it
was funny (a stretch on the minimizing of parentheses). It keeps the
same digits, though; only changes the operators. It's quite clear
that the only symbols -- digits or operators -- we're allowed to add
or remove are ) and (.

Cheers,
Todd

Robert Dober

12/2/2007 1:53:00 PM

0

Here goes my solution for this Quiz, I am confident that solutions 1
and 2 are correct, well 3 too, for 4 that is less sure ;).
Nice to have a quiz which can be solved in less time again.

Robert
###############################
# Read postfix from args or stdin
# Print an infix solution *without* paranthesis
postfix = ARGV.empty? ? $stdin.read.split : ARGV
postfix = postfix.map{ | ele | Integer( ele ) rescue ele }
stack = []
postfix.each do | ele |
case ele
when Integer
stack << ele
else
rhs = stack.pop
stack[ -1 ] = stack[ -1 ].send( ele, rhs )
end
end
puts stack.first.to_s
#########################################################"
# Read postfix from args or stdin
# Print an infix solution with *many* paranthesis

postfix = ARGV.empty? ? $stdin.read.split : ARGV
postfix = postfix.map{ | ele | Integer( ele ) rescue ele }
stack = []
postfix.each do | ele |
case ele
when Integer
stack << ele
else
rhs = stack.pop
stack[ -1 ] = "( #{stack[ -1 ]} ) #{ele} ( #{rhs} )"
end
end

puts stack.first
##################################################
# Read postfix from args or stdin
# Print an infix solution with *some* paranthesis
# the stupid ( and expensive ) way.

class Expression
Combinations = [
["", "", "", ""],
["( ", " )", "", ""],
["", "", "( ", " )"],
["( ", " )", "( ", " )"]
]
attr_reader :text, :value
def initialize text
@value = Integer( text )
@text = text
end
def apply op, rhs
new_text = "#@text #{op} #{rhs.text}"
@value = @value.send( op, rhs.value )
Combinations.each do | parens |
txt = ["", @text, " #{op} ", rhs.text ].
zip( parens ).flatten.join
if eval( txt ) == @value then
return @text = txt
end
end
raise RuntimeError, "ooops"
end
end

postfix = ARGV.empty? ? $stdin.read.split : ARGV
postfix = postfix.map{ | ele | Expression.new( ele ) rescue ele }
stack = []
postfix.each do | ele |
case ele
when Expression
stack << ele
else
rhs = stack.pop
stack.last.apply ele, rhs
end
end

puts stack.first.text
#############################################
# Read postfix from args or stdin
# Print an infix solution with *some* paranthesis
# (the clever way?)

class Expression
Priorities = {
"**" => 2,
"*" => 1, "/" => 1, "%" => 1,
"+" => 0, "-" => 0,
nil => 3
}
Commutative = %w[ * + ]
attr_reader :text, :top_op
def initialize text
@top_op = nil
@text = text
end

def apply op, rhs
@text = parented_text( op ) +
" #{op} " << rhs.parented_text( op, false )
@top_op = op
end

def comm? op
Commutative.include? op
end

def parented_text op, is_lhs=true
my_prio = Priorities[ @top_op ]
op_prio = Priorities[ op ]
return @text if op_prio < my_prio
return "( #@text )" if op_prio > my_prio
return @text if comm?( op ) || is_lhs
"( #@text )"
end

end
postfix = ARGV.empty? ? $stdin.read.split : ARGV
postfix = postfix.map{ | ele |
Expression::Priorities[ ele ] ? ele : Expression.new( ele )
}
stack = []
postfix.each do | ele |
case ele
when Expression
stack << ele
else
rhs = stack.pop
stack[ -1 ].apply ele, rhs
end
end

puts stack.first.text

Eric DUMINIL

12/2/2007 2:29:00 PM

0

Here is my solution:

http://pastie.caboo...
I'm pretty it removes every unnecessary (), at least for - + ** ^ /.


Thanks for the quiz!

On 02/12/2007, Robert Dober <robert.dober@gmail.com> wrote:
> Here goes my solution for this Quiz, I am confident that solutions 1
> and 2 are correct, well 3 too, for 4 that is less sure ;).
> Nice to have a quiz which can be solved in less time again.
>
> Robert
> ###############################
> # Read postfix from args or stdin
> # Print an infix solution *without* paranthesis
> postfix = ARGV.empty? ? $stdin.read.split : ARGV
> postfix = postfix.map{ | ele | Integer( ele ) rescue ele }
> stack = []
> postfix.each do | ele |
> case ele
> when Integer
> stack << ele
> else
> rhs = stack.pop
> stack[ -1 ] = stack[ -1 ].send( ele, rhs )
> end
> end
> puts stack.first.to_s
> #########################################################"
> # Read postfix from args or stdin
> # Print an infix solution with *many* paranthesis
>
> postfix = ARGV.empty? ? $stdin.read.split : ARGV
> postfix = postfix.map{ | ele | Integer( ele ) rescue ele }
> stack = []
> postfix.each do | ele |
> case ele
> when Integer
> stack << ele
> else
> rhs = stack.pop
> stack[ -1 ] = "( #{stack[ -1 ]} ) #{ele} ( #{rhs} )"
> end
> end
>
> puts stack.first
> ##################################################
> # Read postfix from args or stdin
> # Print an infix solution with *some* paranthesis
> # the stupid ( and expensive ) way.
>
> class Expression
> Combinations = [
> ["", "", "", ""],
> ["( ", " )", "", ""],
> ["", "", "( ", " )"],
> ["( ", " )", "( ", " )"]
> ]
> attr_reader :text, :value
> def initialize text
> @value = Integer( text )
> @text = text
> end
> def apply op, rhs
> new_text = "#@text #{op} #{rhs.text}"
> @value = @value.send( op, rhs.value )
> Combinations.each do | parens |
> txt = ["", @text, " #{op} ", rhs.text ].
> zip( parens ).flatten.join
> if eval( txt ) == @value then
> return @text = txt
> end
> end
> raise RuntimeError, "ooops"
> end
> end
>
> postfix = ARGV.empty? ? $stdin.read.split : ARGV
> postfix = postfix.map{ | ele | Expression.new( ele ) rescue ele }
> stack = []
> postfix.each do | ele |
> case ele
> when Expression
> stack << ele
> else
> rhs = stack.pop
> stack.last.apply ele, rhs
> end
> end
>
> puts stack.first.text
> #############################################
> # Read postfix from args or stdin
> # Print an infix solution with *some* paranthesis
> # (the clever way?)
>
> class Expression
> Priorities = {
> "**" => 2,
> "*" => 1, "/" => 1, "%" => 1,
> "+" => 0, "-" => 0,
> nil => 3
> }
> Commutative = %w[ * + ]
> attr_reader :text, :top_op
> def initialize text
> @top_op = nil
> @text = text
> end
>
> def apply op, rhs
> @text = parented_text( op ) +
> " #{op} " << rhs.parented_text( op, false )
> @top_op = op
> end
>
> def comm? op
> Commutative.include? op
> end
>
> def parented_text op, is_lhs=true
> my_prio = Priorities[ @top_op ]
> op_prio = Priorities[ op ]
> return @text if op_prio < my_prio
> return "( #@text )" if op_prio > my_prio
> return @text if comm?( op ) || is_lhs
> "( #@text )"
> end
>
> end
> postfix = ARGV.empty? ? $stdin.read.split : ARGV
> postfix = postfix.map{ | ele |
> Expression::Priorities[ ele ] ? ele : Expression.new( ele )
> }
> stack = []
> postfix.each do | ele |
> case ele
> when Expression
> stack << ele
> else
> rhs = stack.pop
> stack[ -1 ].apply ele, rhs
> end
> end
>
> puts stack.first.text
>
>

Harry Kakueki

12/2/2007 3:09:00 PM

0

>
> This week's quiz is to write a script that translates postfix expressions into
> the equivalent infix expression. In the simplest form, your script should
> function as such:
>
> $ ruby postfix_to_infix.rb '2 3 +'
> 2 + 3
>
> At minimum, try to support the four basic math operators: +, -, *, and /. Feel
> free to add others though. For numbers, remember to accept decimal values.
>
# Here is my solution.
# It solves the minimum requirements with minimal error checking.
# Removes some parentheses.
#str = "1 56 35 + 16 9 - / +"
str = "1 2 - 3 4 - - 2 * 7.4 + 3.14 * 2 / 1.2 + 3 4 - -"
ops = %w[+ - * /]
arr = str.split(/\s+/)
err = arr.select {|c| c =~ /^\d+\.?\d?/ || ops.include?(c)}
the_stack = []

if arr.length == err.length
arr.each_with_index do |x,y|
the_stack << x unless ops.include?(x)
if ops.include?(x) && the_stack.length > 1
b = the_stack.pop
a = the_stack.pop
the_stack << "(#{a} #{x} #{b})" if (x == "+" || x == "-") && (y <
(arr.length - 1))
the_stack << "#{a} #{x} #{b}" if x == "*" || x == "/" || y ==
(arr.length - 1)
end
end
puts the_stack[0]
end

# Harry


--
A Look into Japanese Ruby List in English
http://www.kakueki.com/ruby...

ThoML

12/2/2007 3:35:00 PM

0

> Some people like to work with a postfix notation (often called Reverse Polish
> Notation or just RPN) though, which doesn't require parentheses for the same
> equation:

Since I recently wrote a small RPN calculator in ruby
(http://www.vim.org/scripts/script.php?scri...), I found this
idea interesting.

Here is my take on this. It provides some kind of simplicistic
pattern
matcher and should be extensible. The assumption is made that the
input
consists of numeric data and predefined operators. No error checking
is
done.

Regards,
Thomas.


class Quiz148
class << self
def run(args)
iqueue = args.map {|e| e.split(/\s+/)}.flatten
return Quiz148.new(iqueue).process
end
end

def initialize(iqueue)
@iqueue = iqueue
@depth = 0
@stack = []
@ops = {
'+' => [10],
'-' => [10, [String, String, false, true]],
'*' => [5],
'/' => [5],
'^' => [5, [String, Numeric, true, false]],
}
@opnames = @ops.keys
end

def get_elt(op, idx=-1, other_value=nil)
val = @stack.delete_at(idx)
case val
when Array
eop, val = val
else
eop = nil
end
if op and eop
opp, *opatterns = @ops[op]
eopp, *epatterns = @ops[eop]
if eopp > opp
return '(%s)' % val
end
end
return val
end

def process
@iqueue.each do |token|
if @opnames.include?(token)
val1 = get_elt(token, -2)
val2 = get_elt(token, -1)
@ops[token][1..-1].each do |p1, p2, e1, e2|
if val1.kind_of?(p1) and val2.kind_of?(p2)
val1 = '(%s)' % val1 if e1
val2 = '(%s)' % val2 if e2
break
end
end
@stack << [token, '%s %s %s' % [val1, token, val2]]
else
@stack << eval(token)
end
end
# The stack should include only one element here. A check
would
# be necessary.
get_elt(nil)
end
end

if __FILE__ == $0
if ARGV.empty?
puts Quiz148.run('2 3 +') == '2 + 3'
puts Quiz148.run('56 34 213.7 + * 678 -') == '56 * (34 +
213.7) - 678'
puts Quiz148.run('1 56 35 + 16 9 - / +') == '1 + (56 + 35) /
(16 - 9)'
puts Quiz148.run('1 2 + 3 4 + +') == '1 + 2 + 3 + 4'
puts Quiz148.run('1 2 - 3 4 - -') == '1 - 2 - (3 - 4)'
puts Quiz148.run('2 2 ^ 2 ^') == '(2 ^ 2) ^ 2'
puts Quiz148.run('2 2 2 ^ ^') == '2 ^ 2 ^ 2'
else
puts Quiz148.run(ARGV)
end
end