A Solution to Happy Numbers Problem in JavaScript

Ryan A
4 min readMar 3, 2023

A happy number is a number defined as follows:

Starting with any positive integer, replace the number by the sum of its squares of its digits, and repeat the process until the number equals 1.

If the number is a happy number, it will resolve to 1. If it is a sad number, it will loop endlessly.

Let’s get the first 10,000 happy numbers!

// INSTANTIATE OUR SETS
// WE KNOW 1 IS A HAPPY NUMBER BY DEFINITION
let happyNumbers = new Set([1]);
let sadNumbers = new Set();

// GET FIRST 10,000 HAPPY NUMBERS
for (x = 0; happyNumbers.size < 10000; x++) {
getHappyNumber(x);
}

// RESULT OUTPUT
var finalArray = Array.from(happyNumbers).sort( (a, b) => a - b);
console.log("Happy Numbers: " + finalArray.join(', '));

function getHappyNumber(input) {

// HOLDING ARRAY WILL LET US KEEP TRACK OF CALCULATED SUMS OF SQUARED DIGITS
let holdingArray = [];

while (true) {
// IF HAPPY NUMBER ALREADY HAS IT
// NO NEED TO RECALCULATE, PUSH TO SET OF HAPPY NUMBERS
if (happyNumbers.has(input)) {
holdingArray.forEach(x => happyNumbers.add(x));
break;

// IF WE ARE IN A LOOP OR SAD NUMBER ALREADY HAS IT
// NO NEED TO RECALCULATE, PUSH TO SET OF SAD NUMBERS
} else if (sadNumbers.has(input) || holdingArray.includes(input)) {
holdingArray.forEach(x => sadNumbers.add(x));
break;
}

// PUSH THE NUMBER TO THE HOLDING ARRAY
holdingArray.push(input);

// CALCULATE SUM OF SQUARES
// GOTTA TURN THIS NUMBER INTO A STRING
// AND THEN SPLIT IT INTO AN ARRAY
// AND SUM UP EACH SQUARED VALUE WITH REDUCE
input = input.toString().split('').reduce(
(acc, cur) => acc + (cur ** 2), 0
);
}

}

Time to break this bad boy down.

Let’s start with the basic part, where we turn one number into a sum of its squared digits. That’s the part at the end!

Here’s a example with an input and an output.

let input = 19;

let output = input.toString().split('').reduce(
(acc, cur) => acc + (cur ** 2), 0
);

console.log("Input: " + input + " Output: " + output);
// Input: 19 Output: 82

What we’re doing is:

  1. Taking that number input and turning it into a String
  2. Splitting its digits into an array
  3. Reducing the array by adding each array element (digit) ** 2 (squared) to our initial value of 0

Of course, that 82 would need to be further reduced into 68, which would be reduced to 100, which would be reduced to 1! This means that we now know, by looking at 19, that 19, 82, 68, and 100 are all happy numbers.

We can now examine the whole getHappyNumber() function.

// INSTANTIATE OUR SETS
// WE KNOW 1 IS A HAPPY NUMBER BY DEFINITION
let happyNumbers = new Set([1]);
let sadNumbers = new Set();

// snipping this part for later :)

function getHappyNumber(input) {

// HOLDING ARRAY WILL LET US KEEP TRACK OF CALCULATED SUMS OF SQUARED DIGITS
let holdingArray = [];

while (true) {
// IF HAPPY NUMBER ALREADY HAS IT
// NO NEED TO RECALCULATE, PUSH TO SET OF HAPPY NUMBERS
if (happyNumbers.has(input)) {
holdingArray.forEach(x => happyNumbers.add(x));
break;

// IF WE ARE IN A LOOP OR SAD NUMBER ALREADY HAS IT
// NO NEED TO RECALCULATE, PUSH TO SET OF SAD NUMBERS
} else if (sadNumbers.has(input) || holdingArray.includes(input)) {
holdingArray.forEach(x => sadNumbers.add(x));
break;
}

// PUSH THE NUMBER TO THE HOLDING ARRAY
holdingArray.push(input);

// CALCULATE SUM OF SQUARES
// GOTTA TURN THIS NUMBER INTO A STRING
// AND THEN SPLIT IT INTO AN ARRAY
// AND SUM UP EACH SQUARED VALUE WITH REDUCE
input = input.toString().split('').reduce(
(acc, cur) => acc + (cur ** 2), 0
);
}

}

You’ll notice the first thing we do, outside the function, is instantiate two Sets — happyNumbers and sadNumbers. This will help us keep track of the numbers we’ve already determined to be happy and sad so we don’t waste time recomputing them.

First, we set our temporary holdingArray. This is where we’re going to store our numbers like 19, 82, 68, and so forth, as we calculate.

Next, we enter the while loop, which loops until we hit a break point.

The first thing we do is check whether our happyNumbers Set already has our input number. For example, if we are looking at the number 82, we have presumably already examined 19 and so we would already know 82 is a happy number. No need to go through the whole calculation again — push what we’ve got straight into the happyNumbers Set.

Similarly, we can next check if our sadNumbers Set already has our input number, for the same reason. We also check whether holdingArray already has that number, because if it does we’re stuck in an endless loop which will never resolve to 1, and that’s a sad number. Push it to the sadNumbers Set and stop looping!

If neither condition is satisfied, then we’ve got a brand new number to examine! Push it to our holdingArray for later, and perform our calculation on it.

So, how do we call this to get our first 10,000 happy numbers? We can use a for loop for that!

// GET FIRST 10,000 HAPPY NUMBERS
for (x = 0; happyNumbers.size < 10000; x++) {
getHappyNumber(x);
}

Rather than waiting until x gets to a certain size, we’re just going to loop until our happyNumbers Set reaches a size of 10,000.

Finally, we can output our result!

// RESULT OUTPUT
var finalArray = Array.from(happyNumbers).sort( (a, b) => a - b);
console.log("Happy Numbers: " + finalArray.join(', '));

We create an array out of our happyNumbers Set, and then sort it numerically (since our numbers will all be out of order by default). We can then log this result to our console.

--

--