I've just finished the Reverse Polish Notation task in Julia from rosettacode.com by porting the existing Python code.
There are only a few lines I don't get how to port:
maxcolwidths = [max(len(y) for y in x) for x in zip(*rp)]
and the subsequent lines that use maxcolwidths
.
I managed to pretty print the test output anyway, but I'd really love to hear any opinions from you.
ops = [
:^ => :op_pow,
:* => :op_mul,
:/ => :op_div,
:+ => :op_add,
:- => :op_sub
]
for (op, func) in ops
@eval function ($func)(stack)
b = pop!(stack)
a = pop!(stack)
push!(stack, ($op)(a, b))
end
end
input(prompt::String="") = (print(prompt); inp = chomp(readline()))
get_input(inp::String=input("Expression: ")) = (tokens = split(inp, ' '))
function rpn_calc{T<:String}(tokens::Vector{T}=get_input())
stack = {}
table = ["TOKEN" "ACTION" "STACK"]
for token in tokens
sym = symbol(token)
if sym in keys(ops)
action = "Apply op to top of stack."
@eval $(ops[sym])($stack)
else
action = "Push num onto top of stack."
push!(stack, parse(token))
end
table = [table; token action join([string(s) for s in stack], ' ')]
end
return table
end
function test_rpn(rpn::String="3 4 2 * 1 5 - 2 3 ^ ^ / +")
println("For RPN expression: $rpn")
table = rpn_calc(get_input(rpn))
i = 1
n_rows = length(table[:, 1])
while i <= n_rows
if i == 1
println(join(table[i, 1:2], '\t'), "\t"^4, table[i, 3])
else
println(join(table[i, :], '\t'))
end
i += 1
end
println("\nThe final output value is: $(table[end, 3])")
end
test_rpn()
Output:
For RPN expression: 3 4 2 * 1 5 - 2 3 ^ ^ / + TOKEN ACTION STACK 3 Push num onto top of stack 3 4 Push num onto top of stack 3 4 2 Push num onto top of stack 3 4 2 * Apply op to top of stack 3 8 1 Push num onto top of stack 3 8 1 5 Push num onto top of stack 3 8 1 5 - Apply op to top of stack 3 8 -4 2 Push num onto top of stack 3 8 -4 2 3 Push num onto top of stack 3 8 -4 2 3 ^ Apply op to top of stack 3 8 -4 8 ^ Apply op to top of stack 3 8 65536 / Apply op to top of stack 3 0.0001220703125 + Apply op to top of stack 3.0001220703125 The final output value is: 3.0001220703125
2 Answers 2
In case you don't already know this ...
Here is what the line [max(len(y) for y in x) for x in zip(*rp)]
is doing.
Say that
rp = [('a', 'b', 'c', 'd'), ('aa', 'bbb', 'cccc', 'ddddd')]
unzipped_rp = zip(*rp) # [('a', 'aa'), ('b', 'bbb'), ('c', 'cccc'), ('d', 'ddddd')]
This code does almost the same as what the line above does ...
max_lengths = []
for x in unzipped_rp:
lengths = []
for y in x:
lengths.append(len(y))
max_lengths.append(max(lengths))
print max_lengths
Output: [2, 3, 4, 5]
-
\$\begingroup\$ see docs.python.org/2/library/functions.html#zip \$\endgroup\$jcfollower– jcfollower2014年12月15日 16:55:37 +00:00Commented Dec 15, 2014 at 16:55
In Julia 0.4, the ops initialization causes a warning:
WARNING: deprecated syntax "[a=>b, ...]"
See below for preferred syntax. I don't remember if it works for Julia 0.3.
The use of @eval
twice, once to create functions and once to call them, seems circuitous. A dictionary that maps symbols to functions would be more direct. E.g.:
ops = Dict(
:^ => (x,y)->x^y,
:* => (x,y)->x*y,
:/ => (x,y)->x/y,
:+ => (x,y)->x+y,
:- => (x,y)->x-y
)
The while loop could be written more compactly as for i=1:nrows
.
-
\$\begingroup\$ What I wnated to do was to build the functions programmatically to avoid redundancy. One has to use the
@compat
macro in order to make theDict(:+ => "plus")
syntax work in version 0.3. \$\endgroup\$HarmonicaMuse– HarmonicaMuse2014年12月21日 05:27:28 +00:00Commented Dec 21, 2014 at 5:27
Explore related questions
See similar questions with these tags.