# Calculator with ruby

**URL:** <https://rubytalk.org/t/calculator-with-ruby/69164>\
**Category:** ruby-talk\
**Created:** [15 February 2014 20:36 UTC](https://rubytalk.org/t/calculator-with-ruby/69164 "2014-02-15T20:36:24Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![7stud2](https://avatars.discourse-cdn.com/v4/letter/7/9de053/32.png) [@7stud2](https://rubytalk.org/u/7stud2)\
**Post date:** [15 February 2014 20:36 UTC](https://rubytalk.org/t/calculator-with-ruby/69164/1 "2014-02-15T20:36:24Z")

</div>

Can anybody recommend a better way of creating a calculator than the one  
I have attempted below. I feel my method is inefficient and can be  
optimized.

def calculator(s)  
&nbsp;&nbsp;while true  
&nbsp;&nbsp;&nbsp;&nbsp;s.each\_with\_index do |x,index|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case x  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '\*'  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f \* s[index+1].to\_f  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '/'  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f / s[index+1].to\_f  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;break if !s.include?('\*') and !s.include?('/')  
&nbsp;&nbsp;end  
&nbsp;&nbsp;while true  
&nbsp;&nbsp;&nbsp;&nbsp;s.each\_with\_index do |x,index|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case x  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '+'  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f + s[index+1].to\_f  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '-'  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f - s[index+1].to\_f  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;break if !s.include?('+') and !s.include?('-')  
&nbsp;&nbsp;end  
&nbsp;&nbsp;puts s  
end

calculator(['5','\*','7','+','9','/','3','\*','3'])

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

---

<div class="post-metadata">

**Author:** ![abinoam](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/abinoam/32/1887_2.png) [@abinoam](https://rubytalk.org/u/abinoam)\
**Post date:** [16 February 2014 10:59 UTC](https://rubytalk.org/t/calculator-with-ruby/69164/2 "2014-02-16T10:59:46Z")

</div>

Dear "Zap Zap",

Could you see any "repetition" in your code?  
You can begin by trying to trim them out.

#send will help you out.

10 + 2 #=\> 12  
10.send("+", 2) #=\> 12

Abinoam Jr.

> **···**
>
> On Sat, Feb 15, 2014 at 5:36 PM, Zap Zap \<lists@ruby-forum.com\> wrote:
> 
> > Can anybody recommend a better way of creating a calculator than the one  
> > I have attempted below. I feel my method is inefficient and can be  
> > optimized.
> > 
> > def calculator(s)  
> > &nbsp;&nbsp;while true  
> > &nbsp;&nbsp;&nbsp;&nbsp;s.each\_with\_index do |x,index|  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case x  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '\*'  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f \* s[index+1].to\_f  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '/'  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f / s[index+1].to\_f  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;break if !s.include?('\*') and !s.include?('/')  
> > &nbsp;&nbsp;end  
> > &nbsp;&nbsp;while true  
> > &nbsp;&nbsp;&nbsp;&nbsp;s.each\_with\_index do |x,index|  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case x  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '+'  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f + s[index+1].to\_f  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '-'  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f - s[index+1].to\_f  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;break if !s.include?('+') and !s.include?('-')  
> > &nbsp;&nbsp;end  
> > &nbsp;&nbsp;puts s  
> > end
> > 
> > calculator(['5','\*','7','+','9','/','3','\*','3'])
> > 
> > --  
> > Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Jesus\_Gabriel\_y\_Gala](https://avatars.discourse-cdn.com/v4/letter/j/96bed5/32.png) [@Jesus\_Gabriel\_y\_Gala](https://rubytalk.org/u/Jesus_Gabriel_y_Gala)\
**Post date:** [17 February 2014 08:34 UTC](https://rubytalk.org/t/calculator-with-ruby/69164/3 "2014-02-17T08:34:04Z")

</div>

Apart from others' comments which are interesting, I wanted to show  
how I'd do a simple evaluator, which is similar to your approach but  
using a temporary array to avoid so much slicing:

def is\_high\_precedence\_operator o  
&nbsp;&nbsp;&nbsp;&nbsp;o == '\*' || o == '/'  
end

def calculate tokens  
&nbsp;&nbsp;&nbsp;&nbsp;temp =   
&nbsp;&nbsp;&nbsp;&nbsp;tokens.each do |t|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if is\_high\_precedence\_operator(temp.last)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;operator = temp.pop  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;first = temp.pop.to\_i  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.push first.send(operator, t.to\_i)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.push t  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;total = temp.first.to\_i  
&nbsp;&nbsp;&nbsp;&nbsp;temp[1..-1].each\_cons(2) do |op,second|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;total = total.send(op,second.to\_i)  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;total  
end

calculate %w{5 \* 7 + 9 / 3 \* 3}

Hope this helps,

Jesus.

> **···**
>
> On Sat, Feb 15, 2014 at 9:36 PM, Zap Zap \<lists@ruby-forum.com\> wrote:
> 
> > Can anybody recommend a better way of creating a calculator than the one  
> > I have attempted below. I feel my method is inefficient and can be  
> > optimized.
> > 
> > def calculator(s)  
> > &nbsp;&nbsp;while true  
> > &nbsp;&nbsp;&nbsp;&nbsp;s.each\_with\_index do |x,index|  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case x  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '\*'  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f \* s[index+1].to\_f  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '/'  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f / s[index+1].to\_f  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;break if !s.include?('\*') and !s.include?('/')  
> > &nbsp;&nbsp;end  
> > &nbsp;&nbsp;while true  
> > &nbsp;&nbsp;&nbsp;&nbsp;s.each\_with\_index do |x,index|  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case x  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '+'  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f + s[index+1].to\_f  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '-'  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f - s[index+1].to\_f  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;break if !s.include?('+') and !s.include?('-')  
> > &nbsp;&nbsp;end  
> > &nbsp;&nbsp;puts s  
> > end
> > 
> > calculator(['5','\*','7','+','9','/','3','\*','3'])
> > 
> > --  
> > Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![7stud2](https://avatars.discourse-cdn.com/v4/letter/7/9de053/32.png) [@7stud2](https://rubytalk.org/u/7stud2)\
**Post date:** [17 February 2014 16:47 UTC](https://rubytalk.org/t/calculator-with-ruby/69164/4 "2014-02-17T16:47:11Z")

</div>

Zap Zap wrote in post #1136795:

> Can anybody recommend a better way ....

if better is less code lines,..., this one :

expr=ARGV.join("")  
loop {  
&nbsp;&nbsp;expr.gsub!(/(\d+)([\/\*])(\d+)/) { $1.to\_i.send($2,$3.to\_i).to\_s}  
&nbsp;&nbsp;expr.gsub!(/(\d+)([+-])(\d+)/) { $1.to\_i.send($2,$3.to\_i).to\_s }  
&nbsp;&nbsp;(puts expr; break ) if expr =~/^\d+$/  
}

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Tamara\_Temple1](https://avatars.discourse-cdn.com/v4/letter/t/5f9b8f/32.png) [@Tamara\_Temple1](https://rubytalk.org/u/Tamara_Temple1)\
**Post date:** [16 February 2014 15:23 UTC](https://rubytalk.org/t/calculator-with-ruby/69164/5 "2014-02-16T15:23:19Z")

</div>

Abinoam's advice is great: first reduce repetition.

If you are up for a bit of a challenge, you might look at how you can  
make your calculator "parse" your in-fix notation array of tokens into  
a pre-fix structure, that you can then reduce to the result. Good fun!

> **···**
>
> On Sun, Feb 16, 2014 at 4:59 AM, Abinoam Jr. \<abinoam@gmail.com\> wrote:
> 
> > Dear "Zap Zap",
> > 
> > Could you see any "repetition" in your code?  
> > You can begin by trying to trim them out.
> > 
> > #send will help you out.
> > 
> > 10 + 2 #=\> 12  
> > 10.send("+", 2) #=\> 12
> > 
> > Abinoam Jr.
> > 
> > On Sat, Feb 15, 2014 at 5:36 PM, Zap Zap \<lists@ruby-forum.com\> wrote:
> > 
> > > Can anybody recommend a better way of creating a calculator than the one  
> > > I have attempted below. I feel my method is inefficient and can be  
> > > optimized.
> > > 
> > > def calculator(s)  
> > > &nbsp;&nbsp;while true  
> > > &nbsp;&nbsp;&nbsp;&nbsp;s.each\_with\_index do |x,index|  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case x  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '\*'  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f \* s[index+1].to\_f  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '/'  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f / s[index+1].to\_f  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > > &nbsp;&nbsp;&nbsp;&nbsp;break if !s.include?('\*') and !s.include?('/')  
> > > &nbsp;&nbsp;end  
> > > &nbsp;&nbsp;while true  
> > > &nbsp;&nbsp;&nbsp;&nbsp;s.each\_with\_index do |x,index|  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case x  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '+'  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f + s[index+1].to\_f  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '-'  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f - s[index+1].to\_f  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > > &nbsp;&nbsp;&nbsp;&nbsp;break if !s.include?('+') and !s.include?('-')  
> > > &nbsp;&nbsp;end  
> > > &nbsp;&nbsp;puts s  
> > > end
> > > 
> > > calculator(['5','\*','7','+','9','/','3','\*','3'])
> > > 
> > > --  
> > > Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![abinoam](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/abinoam/32/1887_2.png) [@abinoam](https://rubytalk.org/u/abinoam)\
**Post date:** [17 February 2014 10:20 UTC](https://rubytalk.org/t/calculator-with-ruby/69164/6 "2014-02-17T10:20:25Z")

</div>

Dear Zap Zap,

Basically I just tried to trim the repetition maintaining (at least  
partially) your original approach.

def calculator(s)  
&nbsp;&nbsp;response = s.dup  
&nbsp;&nbsp;[['\*', '/'], ['+', '-']].each do |ops|  
&nbsp;&nbsp;&nbsp;&nbsp;ix = 0  
&nbsp;&nbsp;&nbsp;&nbsp;while s[ix]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ops.include? s[ix+1]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n1, op, n2 = s[ix,3]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[ix,3] = n1.to\_f.send(op, n2.to\_f)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ix += 2  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end  
&nbsp;&nbsp;s[0]  
end

Abinoam Jr.

> **···**
>
> On Mon, Feb 17, 2014 at 5:34 AM, Jesús Gabriel y Galán \<jgabrielygalan@gmail.com\> wrote:
> 
> > On Sat, Feb 15, 2014 at 9:36 PM, Zap Zap \<lists@ruby-forum.com\> wrote:
> > 
> > > Can anybody recommend a better way of creating a calculator than the one  
> > > I have attempted below. I feel my method is inefficient and can be  
> > > optimized.
> > > 
> > > def calculator(s)  
> > > &nbsp;&nbsp;while true  
> > > &nbsp;&nbsp;&nbsp;&nbsp;s.each\_with\_index do |x,index|  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case x  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '\*'  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f \* s[index+1].to\_f  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '/'  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f / s[index+1].to\_f  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > > &nbsp;&nbsp;&nbsp;&nbsp;break if !s.include?('\*') and !s.include?('/')  
> > > &nbsp;&nbsp;end  
> > > &nbsp;&nbsp;while true  
> > > &nbsp;&nbsp;&nbsp;&nbsp;s.each\_with\_index do |x,index|  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case x  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '+'  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f + s[index+1].to\_f  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when '-'  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = s[index-1].to\_f - s[index+1].to\_f  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s[index-1] = result  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s.slice!(index,2)  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > > &nbsp;&nbsp;&nbsp;&nbsp;break if !s.include?('+') and !s.include?('-')  
> > > &nbsp;&nbsp;end  
> > > &nbsp;&nbsp;puts s  
> > > end
> > > 
> > > calculator(['5','\*','7','+','9','/','3','\*','3'])
> > > 
> > > --  
> > > Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).
> > 
> > Apart from others' comments which are interesting, I wanted to show  
> > how I'd do a simple evaluator, which is similar to your approach but  
> > using a temporary array to avoid so much slicing:
> > 
> > def is\_high\_precedence\_operator o  
> > &nbsp;&nbsp;&nbsp;&nbsp;o == '\*' || o == '/'  
> > end
> > 
> > def calculate tokens  
> > &nbsp;&nbsp;&nbsp;&nbsp;temp =   
> > &nbsp;&nbsp;&nbsp;&nbsp;tokens.each do |t|  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if is\_high\_precedence\_operator(temp.last)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;operator = temp.pop  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;first = temp.pop.to\_i  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.push first.send(operator, t.to\_i)  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;temp.push t  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;total = temp.first.to\_i  
> > &nbsp;&nbsp;&nbsp;&nbsp;temp[1..-1].each\_cons(2) do |op,second|  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;total = total.send(op,second.to\_i)  
> > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;total  
> > end
> > 
> > calculate %w{5 \* 7 + 9 / 3 \* 3}
> > 
> > Hope this helps,
> > 
> > Jesus.

---

<div class="post-metadata">

**Author:** ![Stu1](https://avatars.discourse-cdn.com/v4/letter/s/49beb7/32.png) [@Stu1](https://rubytalk.org/u/Stu1)\
**Post date:** [17 February 2014 06:45 UTC](https://rubytalk.org/t/calculator-with-ruby/69164/7 "2014-02-17T06:45:52Z")

</div>

Also to add to tamouse's suggestion implement parens based precedence into  
your parser.

> **···**
>
> On Sun, Feb 16, 2014 at 9:23 AM, tamouse pontiki \<tamouse.lists@gmail.com\>wrote:
> 
> > On Sun, Feb 16, 2014 at 4:59 AM, Abinoam Jr. \<abinoam@gmail.com\> wrote:  
> > \> Dear "Zap Zap",  
> > \>  
> > \> Could you see any "repetition" in your code?  
> > \> You can begin by trying to trim them out.  
> > \>  
> > \> #send will help you out.  
> > \>  
> > \> 10 + 2 #=\> 12  
> > \> 10.send("+", 2) #=\> 12  
> > \>  
> > \> Abinoam Jr.  
> > \>  
> > \> On Sat, Feb 15, 2014 at 5:36 PM, Zap Zap \<lists@ruby-forum.com\> wrote:  
> > \>\> Can anybody recommend a better way of creating a calculator than the one  
> > \>\> I have attempted below. I feel my method is inefficient and can be  
> > \>\> optimized.  
> > \>\>  
> > \>\> def calculator(s)  
> > \>\> while true  
> > \>\> s.each\_with\_index do |x,index|  
> > \>\> case x  
> > \>\> when '\*'  
> > \>\> result = s[index-1].to\_f \* s[index+1].to\_f  
> > \>\> s[index-1] = result  
> > \>\> s.slice!(index,2)  
> > \>\> break  
> > \>\> when '/'  
> > \>\> result = s[index-1].to\_f / s[index+1].to\_f  
> > \>\> s[index-1] = result  
> > \>\> s.slice!(index,2)  
> > \>\> break  
> > \>\> end  
> > \>\> end  
> > \>\> break if !s.include?('\*') and !s.include?('/')  
> > \>\> end  
> > \>\> while true  
> > \>\> s.each\_with\_index do |x,index|  
> > \>\> case x  
> > \>\> when '+'  
> > \>\> result = s[index-1].to\_f + s[index+1].to\_f  
> > \>\> s[index-1] = result  
> > \>\> s.slice!(index,2)  
> > \>\> break  
> > \>\> when '-'  
> > \>\> result = s[index-1].to\_f - s[index+1].to\_f  
> > \>\> s[index-1] = result  
> > \>\> s.slice!(index,2)  
> > \>\> break  
> > \>\> end  
> > \>\> end  
> > \>\> break if !s.include?('+') and !s.include?('-')  
> > \>\> end  
> > \>\> puts s  
> > \>\> end  
> > \>\>  
> > \>\> calculator(['5','\*','7','+','9','/','3','\*','3'])  
> > \>\>  
> > \>\> --  
> > \>\> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).
> > 
> > Abinoam's advice is great: first reduce repetition.
> > 
> > If you are up for a bit of a challenge, you might look at how you can  
> > make your calculator "parse" your in-fix notation array of tokens into  
> > a pre-fix structure, that you can then reduce to the result. Good fun!
