Question

Can someone help me understand the below answer? I know it's the correct answer to make the following rspec test pass. Also is there a different/simpler way to implement this? As I don't understand how it does it.

 def tokens(string)
    string.split.map{|s| s[/\d/] ? s.to_i : s.to_sym}
 end

 def evaluate(pol)
        order = []
        opps = {:+ => plus, :- => minus, :/ => divide, :* => times }
        tokens(pol).reverse.chunk{|n| n.is_a?(Integer)}.each{|e,a| e == true ? a.reverse.each{|a| push(a) } : a.each {|a| order.push(a) }}
        order.reverse.each {|o| (opps[o]) }   end

rspec test:

# extra credit
  it "tokenizes a string" do
    calculator.tokens("1 2 3 * + 4 5 - /").should ==
      [1, 2, 3, :*, :+, 4, 5, :-, :/]
  end

  # extra credit
  it "evaluates a string" do
    calculator.evaluate("1 2 3 * +").should ==
      ((2 * 3) + 1)

    calculator.evaluate("4 5 -").should ==
      (4 - 5)

    calculator.evaluate("2 3 /").should ==
      (2.0 / 3.0)

    calculator.evaluate("1 2 3 * + 4 5 - /").should ==
      (1.0 + (2 * 3)) / (4 - 5)
  end
Était-ce utile?

La solution

For those struggling with this Test Ruby, rspec test, I've managed to breakdown the method above and understand it as below:

Step 1

    1. Define operators as procs

Step 2

    2. Utilize Token method to generate the following token = [1, 2, 3, :*, :+]

Step 3

    3. Check if integer and chunk accordingly

Step 4

    4. Check result after chunking, and value of @stack
    # ==> [true, [1,2,3]] / @stack = [1, 2, 3]
    # ==> [false, [:*, *+]] @stack = [1, 2, 3 * +]

Step 5

    5. When reaching an operator, the appropriate method is called
    # Calls times -> @stack.push(@stack.pop * @stack.pop)
    # (3 * 2)
    # Calls plus -> @stack.push(@stack.pop + @stack.pop)

Rspec test should pass now

(3 * 2) + 1

Method after editing

def evaluate(pol)
    @stack = []

    opps = {
        :+ => Proc.new {plus}, 
        :- => Proc.new{minus}, 
        :/ => Proc.new{divide}, 
        :* => Proc.new{times} 
        }

    tokens(pol).chunk{|n| n.is_a?(Integer)}.each do |condition, chunk|
        if condition == true
            chunk.each{|a| push(a) }
        else
            chunk.each {|o| (opps[o].call)}
        end
    end
    @stack[0]
end
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top