6
\$\begingroup\$

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
\$\endgroup\$
3
\$\begingroup\$

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]

\$\endgroup\$
3
\$\begingroup\$

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.

\$\endgroup\$
  • \$\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 the Dict(:+ => "plus") syntax work in version 0.3. \$\endgroup\$ – SalchiPapa Dec 21 '14 at 5:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.