Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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
share|improve this question
up vote 3 down vote accepted

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]

share|improve this answer
    

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.

share|improve this answer
    
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. – Ismael Venegas Castelló Dec 21 '14 at 5:27

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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