Alex Hail Alex Hail - 1 month ago 12
Ruby Question

Ruby calculator - hash not storing correctly

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!

Examples format

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]}
Comments