Programming used to be a much bigger hobby for me than it is now.

When I was about 15, my father bought me a MacBook so I could attempt iPhone development, this went nowhere. Instead, I dicked around and coded other random crap that nobody cared about. Which is fine. It was a lot of fun.

During this time, Ruby was my language of choice. I absolutely loved playing around with it. It’s a great language.

I had also learned about RPN calculators, and gave a go at creating an RPN calculator in Ruby, and decided to code golf it.

This is what I came up with.

p((_=[gets.split,[],"+-**/"])[0].map{|s|s=~/[\d\.]+/?_[1]<<s.to_f: _[2][s]?_[1]<<_[1].pop(2).inject(s):0}[0][0])

It’s an RPN calculator that supports floating point numbers and can perform addition, subtraction, multiplication, division and powers.

I wrote this back in July of 2012 and I figured I’d go through and post this again for posterity, and explain how the code works.

First, I’ll break the code up to make it slightly more readable.

p(
  (_=[gets.split, [], "+-**/"])[0].map{|s|
    s=~/[\d\.]+/ ?
      _[1]<<s.to_f
      : _[2][s] ?
        _[1] << _[1].pop(2).inject(s)
        : 0
  }[0][0])

And now line by line.

p((

Once we get the result, print it. Ruby’s Kernel#p method is very handy for code golfing, although it’s completely different than Kernel#puts.

_=[gets.split, [], "+-**/"]

The array _ is defined with three elements. The first is the user’s input split by whitespace. Parens are optional in Ruby and the default behavior of String#split is to split on whitespace. The second element is an empty array, which is used for the calculator’s stack, and the last element is a string containing all the valid operators. ** is there because the power operator in Ruby is ** which is handy because this also covers the multiplication operator.

(_=...)[0].map{|s|

This bit is equivalent to saying _[0].map{ |s| # .... We map through each element of the user input with s as the current element. Because we defined _ before running the map operation, we can access _ from within the map block.

s=~/[\d\.]+/ ?

This performs a regex match test on our current input element which will pass if it is a valid floating point number. You’ll probably notice that this will also pass invalid numbers like 1.2.3 but when we call String#to_f on this later, Ruby will just throw out the .3 part and return 1.2. We use the ternary operator to perform this next line if the string matches a number.

_[1]<<s.to_f

This pushes the number onto the stack converted to a float. << is infix notation for Array#push.

: _[2][s] ?

As the “else” part of this first ternary, we now test to see if our current input element is a substring of the allowed operators string, "+-**/". This takes advantage of one of one of the ways to perform a substring search in Ruby. Here’s some examples of this syntax.

"test"["te"]  # => "te"
"test"["st"]  # => "st"
"test"["abc"] # => nil
"test"["tea"] # => nil

Since nil is falsy and a String is truthy, we can use this to test if our allowed operators string contains the current user input element as a substring.

If we know we have a valid operator, we perform the following:

_[1] << _[1].pop(2).inject(s)

This pops two elements from the stack, applies our operator string to them using Enumerable#inject (since infix mathematical operators aren’t anything special, just regular method calls) and then pushes the result back onto the stack.

Normally inject is called with a block like such:

inject { |accum, obj| # ...

Where accum is the accumulator value and obj is the current element. This can be used to sum up a list of numbers:

[1, 2, 3, 4].inject { |sum, n| sum + n }

This is similar to what we’re doing, but we’re calling inject with a symbol (implicitly converted from our string operator) instead of a block as its argument. So the first element is taken as accum, the second element as obj and they’re combined with Enumerable#inject to produce the result of the operation on the two elements.

: 0

And then, this happens if the current input element wasn’t a number or valid operator. Just return 0. An “else” expression is required when using the ternary operator, and this is the shortest way to accomplish that.

And now the final bit.

}[0][0])

We get our result so it can be printed.

This array access is required because of how we used Array#map. If we look at our ternary operator, our three possible outcomes are:

  1. _[1] << s.to_f
  2. _[1] << _[1].pop(2).inject(s)
  3. 0

We’re mapping over the input element array, so we’ll get an array out with the same length as the input element array, and each item will be replaced with one of these returned values.

Since Array#push returns the newly modified Array object (not a distinct copy of it), we’re placing _[1] into the result of the map operator for every input element that was a valid number or operator. Otherwise, we place 0.

Consider the input string: 1 2 a +

Our calculator will output 3.0 which is the correct result if we assume we want to throw away invalid inputs. If we take away the [0][0] we’ll get: [[3.0], [3.0], 0, [3.0]].

Every element that had valid input will now hold _[1], the stack, and modifications to the stack reflect over this entire final array.

This has the side effect that if the first character of our input string is not a valid number or operator, the output will be 0 no matter the actual result of the calculation.

My original solution was 138 characters, but with the input from some other folks, we now have this 112 character version that has somehow not been lost over 7 years.

I doubt anyone will find this useful, but I wanted to preserve it.