Alex Hail - 6 months ago 28

Ruby Question

So I'll start off by writing that I am new to this site (today), as well as to the Ruby programming language (3 days ago), so don't feel afraid to rip apart my code--I am trying to learn and get better.

Basically.. I am creating a console calculator that is able to read a simple math problem (or string of math problems) from the user and solve the equation. It doesn't use order of operations or anything fancy (yet) and it is basically working except for this one weird bug I can't figure out.

`Userinput = "1 + 2 + 3 - 4"`

# First I split the user input into an array of stirngs and then loop over the

# array of strings and depict whether a string is a key or hash (see code below)

# program should store these characters in a hash like so..

hash = { nil=>1, "+"=>2, "+"=>3, "-"=>4 }

Then I would use the key of the hash to determine whether or not I was adding, subtracting, multiplying, or dividing next.

Everything pretty much works fine! Its just that when I do a problem with more than 2 operations (i.e. 1 + 2 - 0 + 3) the program will just randomly leave out some keys and operators. I have been trying different examples to search for a pattern but I cant find the source. Below I'll post examples of the problem and their output, as well as the hash itself, and then full source code. Thanks in advance for any help or critiques!

Program Input (user prompt, user input) --

Program output (sum of equation) --

hash at the end of execution

Example 1

Type a math problem (ex. 40 / 5): 40 / 5 + 2 - 5 * 5 - 5 * 5 - 100

-450

{nil=>40, "/"=>5, "+"=>2, "-"=>100, "*"=>5}

Example 2

Type a math problem (ex. 40 / 5): 1 + 2 - 0 + 3

4

{nil=>1, "+"=>3, "-"=>0}

Example 3

Type a math problem (ex. 40 / 5): 10 - 5 * 2 + 8 + 2

12

{nil=>10, "-"=>5, "*"=>2, "+"=>2}

Source code: main.rb

`=begin`

main.rb

Version 1.0

Written by Alex Hail - 10/16/2016

Parses a basic, user-entered arithmetic equation and solves it

=end

@operationsParser = "" # global parser

@lastKeyAdded = ""

private

def appointType(sv)

if sv =~ /\d/

sv.to_i

else

sv

end

end

private

def operate(operations)

sum = 0

operations.each do |k, v|

if k.nil?

sum += v

else

case k

when '+' then sum += v

when '-' then sum -= v

when '*' then sum = sum * v

when '/' then sum = sum / v

else

end

end

end

sum

end

private

def solveEquation

print "Type a math problem (ex. 40 / 5): "

userInput = gets.chomp

#array to hold all numbers and their cooresponding operation

operations = {} # <== Empty hash

#split the user input via spaces

@operationsParser = userInput.split(" ")

#convert numbers into numbers store operators in hash ( nil => 40, "/" => 5) -- would be 40 / 5

@operationsParser.each do |stringValue|

if appointType(stringValue).is_a? Integer

operations[@lastKeyAdded != "" ? @lastKeyAdded : nil] = appointType(stringValue)

else #appointType will return a string by default

keyToAdd = appointType(stringValue)

@lastKeyAdded = keyToAdd

end

end

#check if operators(+, *, -, /, or nil) in the keys are valid, if not, error and exit, if so, operate

operations.each do |k,v|

case k

when '+'

when '-'

when '*'

when '/'

when nil

else

# Exit the program if we have an invalid operator in the hash

puts "Exiting program with error - Invalid operator used (Only +, -, *, / please)"

return

end

end

sum = operate(operations)

puts sum, operations

end

solveEquation

Answer

Ok so the problem is the data structure that you chose, a hash by definition has to always maintain a set of unique keys to map to its values. Now something you could try if you are dead set on using a hash is mapping all the keys to empty arrays then add numerical values to that then process that operation on every value in it respective array(since you are ignoring order of operations any way)

```
h = Hash.new([]) #to set the default value of each key to an empty arrary
```

then when you process your array it should look like this

```
{nil =>[1], '+' => [1, 2, 3], '-' => [3, 7], '*' => [4, 47], '/' => [3, 5]}
```