patternjavascriptMinor
PE # 34 - "Digit Factorials" with no loops
Viewed 0 times
withdigitloopsfactorials
Problem
I posted a similar question “Curious Numbers” (HackerRank PE 34) recently (but in a different language/platform altogether). I'm starting to learn JavaScript and decided to take the challenge again and adapt it to this language's features and quirks.
While I could have written many of the functions below using for-loops, I decided instead to focus on getting better with the FP aspects of JS, in particular
I think it is pretty fast, with the longest of the 5 challenges on HackerRank executing in 2.28s for a calculation in the neighborhood of \$10^5\$, but I'm certainly open to ways to make it faster, cleaner, or better in any other way.
\$19!\$ is a curious number, as \$1!+9!=1+362880=362881\$ is divisible
by \$19\$.
Find the sum of all numbers below \$N\$ which divide the sum of the
factorial of their digits. Note: as \$1!,2!,\cdots,9!\$ are not sums, so they are not included.
Input Format: Input contains an integer \$N\$
Output Format: Print the answer corresponding to the test case.
Constraints: \$10^1 \le N \le 10^5\$
Sample Input
Sample Output
```
// HackerRank Project Euler #34: Digit factorials
// https://www.hackerrank.com/contests/projecteuler/challenges/euler034
function isStrictInt(input) {
// Confirms whether input is 1) of number type, 2) not equal to the NaN constant, and 3) can be parsed to an integer.
// Reference: http://stackoverflow.com/a/29658971/3626537
return typeof input === "number"
&& !isNaN(input)
&& parseInt(input) === input;
}
function arrayOfNCopies(value, N) {
// Makes an array of N copies of value.
if (!isStrictInt(N)) {
return NaN;
}
else if (N === 0) {
return [];
}
return Array(Math.abs(N) + 1).join(value).split("");
}
function arrayOfNConsecutiveInts(N) {
// Makes an array of consecutive integers from 1 to N.
// Ex: arrayOfNConsecut
While I could have written many of the functions below using for-loops, I decided instead to focus on getting better with the FP aspects of JS, in particular
map, reduce, filter and apply. I think it is pretty fast, with the longest of the 5 challenges on HackerRank executing in 2.28s for a calculation in the neighborhood of \$10^5\$, but I'm certainly open to ways to make it faster, cleaner, or better in any other way.
\$19!\$ is a curious number, as \$1!+9!=1+362880=362881\$ is divisible
by \$19\$.
Find the sum of all numbers below \$N\$ which divide the sum of the
factorial of their digits. Note: as \$1!,2!,\cdots,9!\$ are not sums, so they are not included.
Input Format: Input contains an integer \$N\$
Output Format: Print the answer corresponding to the test case.
Constraints: \$10^1 \le N \le 10^5\$
Sample Input
20Sample Output
19```
// HackerRank Project Euler #34: Digit factorials
// https://www.hackerrank.com/contests/projecteuler/challenges/euler034
function isStrictInt(input) {
// Confirms whether input is 1) of number type, 2) not equal to the NaN constant, and 3) can be parsed to an integer.
// Reference: http://stackoverflow.com/a/29658971/3626537
return typeof input === "number"
&& !isNaN(input)
&& parseInt(input) === input;
}
function arrayOfNCopies(value, N) {
// Makes an array of N copies of value.
if (!isStrictInt(N)) {
return NaN;
}
else if (N === 0) {
return [];
}
return Array(Math.abs(N) + 1).join(value).split("");
}
function arrayOfNConsecutiveInts(N) {
// Makes an array of consecutive integers from 1 to N.
// Ex: arrayOfNConsecut
Solution
Your code looks very nice.
Built-ins
Your
This also means you won't need
Consistent return values
You've done a good job doing type checking so your functions don't receive invalid inputs. But, sometimes your return values don't make sense (I only found one case).
Here: your
It's best to be consistent with your return types. Here, it might be best to throw an error.
I'm not 100% sure about this.
Refactor array summing
This construct
has a few flaws, in my opinion:
Also, while I'm not that familiar with it, is it still good practice in FP when one of a method's inputs is the object itself?
Either way, this could refactored to a separate function:
Or, if you use ES6 in the future, it could look even cleaner:
Nitpicks
-
This:
can be simplified to:
Built-ins
Your
powerOf function is mimicking Math.pow exactly. Use the built-in instead.This also means you won't need
arrayOfNCopies now.Consistent return values
You've done a good job doing type checking so your functions don't receive invalid inputs. But, sometimes your return values don't make sense (I only found one case).
Here: your
arrayOfNConsecutiveInts returns NaN if N isn't a valid number, but an entirely different type - an array - if it is valid.It's best to be consistent with your return types. Here, it might be best to throw an error.
I'm not 100% sure about this.
Refactor array summing
This construct
.reduce(function (a, b) {
return a + b;
});has a few flaws, in my opinion:
- It's not very understandable at first glace (at least in my opinion, but I'm sure others will disagree).
- You repeat it a lot.
Also, while I'm not that familiar with it, is it still good practice in FP when one of a method's inputs is the object itself?
Either way, this could refactored to a separate function:
function sumArray(arr) {
... type checking...
arr.reduce(function(a, b) {
return a + b;
});
}Or, if you use ES6 in the future, it could look even cleaner:
let sumArray = (arr) => arr.reduce((a, b) => a + b);Nitpicks
- Always supply
parseIntwith its secondradixparameter.
-
This:
else if (sumOfFactorialOfDigits(N) % N !== 0) {
return false;
}
return true;can be simplified to:
return sumOfFactorialOfDigits(N) % N === 0Code Snippets
.reduce(function (a, b) {
return a + b;
});function sumArray(arr) {
... type checking...
arr.reduce(function(a, b) {
return a + b;
});
}let sumArray = (arr) => arr.reduce((a, b) => a + b);else if (sumOfFactorialOfDigits(N) % N !== 0) {
return false;
}
return true;return sumOfFactorialOfDigits(N) % N === 0Context
StackExchange Code Review Q#123245, answer score: 3
Revisions (0)
No revisions yet.