Happy Number with Ruby

Derek Cerretani
3 min readApr 2, 2020

--

Photo by Antoine Boissonot on Unsplash

What’s a happy number? Here’s how LeetCode describes one.

A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.

Here’s an example.

Input: 19

Output: true

Explanation:

1² + 9² = 82

8² + 2² = 68

6² + 8² = 100

1² + 0² + 0² = 1

Let’s create a method called #is_happy and pass in an integer, n, as a parameter.

def is_happy(n)
end

Let’s follow the example and set n = 19. First, if we want to add each individual digit in 19, let’s split it up into 1 and 9 using the #split method. We can’t split an integer in Ruby, so first, we need to convert 19 into a string.

def is_happy(n)    arr = n.to_s.split("") => ["1", "9"]end

Now let’s iterate over the array with #map. Our logic in #map needs to turn each string in our array back into an integer and square it.

def is_happy(n)    arr = n.to_s.split("") => ["1", "9"]    arr.map do |str|
str.to_i ** 2
end
end

Mapping over arr, in this way, returns a new array [1, 81].
Ruby has an excellent #sum method we can attach to our #map iterator and sum the contents of our new array.

arr.map do |str|
str.to_i ** 2
end.sum
// 82

#Sum takes the contents of our array ([ 1, 81 ]), adds them all together, and returns the integer, 82.

Based on the example above, 82 is precisely what we’re looking for. We know we want to perform the same operations on 82, so let’s wrap our code into a method called, #add_split, we can call each time with our newly returned integer.

def is_happy(n)    def add_split(num)        arr = num.to_s.split("")        arr.map do |str|            str.to_i ** 2        end.sum    end
end

Since we want to repeat this process until n = 1, or we get stuck in a loop (and n never equals one), let’s set the return value of #add_split equal to a new variable, i. Then we’ll call #add_split with our new variable until either it equals 1 or we find ourselves stuck in a loop.

i = add_split(n)until i == 1
i == add_split(i)
end

The above works if our i variable ever equals one, but how can we know if we’re stuck in a loop? I was working in VSCode while solving this problem, and since I have the pry gem installed, I required pry in my file and stuck a binding.pry before our until loop.

i = add_split(n)binding.pryuntil i == 1 ...

Using trial and error, I then called the #is_happy method, passing in 20 as the argument. Stuck in the pry, I called i = add_split(i) to see if i would ever equal 1. Instead, I found myself stuck in a loop. It turns out that when i never equals 1 it loops through the following numbers, 145, 42, 20, 4, 16, 37, 58, and 89.

I tried passing in other arguments and always got stuck in the same loop. To exit our until loop when n isn’t happy, we can add an or ( || ) to our conditional to see if i ever equals one of the looped numbers.

until i == 1 || i == 4
i == add_split(i)
end

Then once our until loop exits, we can use a simple ternary statement to return true or false.

i == 1 ? true : false

Here’s the entire method.

def is_happy(n)

def add_split(num)
arr = num.to_s.split("")
arr.map do |str|
str.to_i ** 2
end.sum
end
i = add_split(n)

until i == 1 || i == 4
i = add_split(i)
end
i == 1 ? true : false

end

And there it is! Please share your solutions below!

If you’d like to connect, you can reach me on Twitter and LinkedIn.

--

--