Reputation: 13
I am trying to find the average the sum of digits of a number.
For example, for the number 123, the sum of digits of 123 is 6 and the number of digits in 123 is 3. So, the average of digits of 123 is 6/3 = 2.
I've only gotten as far as trying to find the sum through recursion unfortunately and often comes up as undefined. If I could figure this out I could find the average comfortably.
function averageOfDigits(number) {
// Make the whole number into a string first to get the individual digits
let arrOfStr = number.toString().split('');
// Convert this array into integers
let arrOfNum = arrOfStr.map(parseFloat)
// Find sum of these digits using recursion
let sum = function sumRecursion (arrOfNum) {
if (arrOfNum.length === 1) {
return arrOfNum[0]
} else {
return arrOfNum.pop() + sum(arrOfNum)
}
}
}
console.log(averageOfDigits(999))
Upvotes: 1
Views: 401
Reputation: 50807
There are several interesting alternative recursive approaches. Our first one treats the number as a string and proceeds from there:
const _avgOfDigits = ([d, ...ds], total, count) =>
d == undefined
? total / count
: _avgOfDigits (ds, total + Number (d), count + 1)
const avgOfDigits = (n) =>
_avgOfDigits (String (n) .split (''), 0, 0)
console .log (avgOfDigits (8675309)) //=> 5.428571428571429
Here we have a shell function that turns our number into an array of single-digit strings, then calls the private recursive function passing that array, and zeros for total and count. Our private function separates off the first digit and adds it to the total, increments the count, and recurs with these values and the remaining digits. When there are no more digits we return the quotient of the total and the digit count.
Our second one is more mathematical:
const avgOfDigits = (n, total = 0, count = 0) =>
n == 0
? total / count
: avgOfDigits (Math .floor (n / 10), total + n % 10, count + 1)
console .log (avgOfDigits (8675309)) //=> 5.428571428571429
Here we deal with the last digit and the remaining ones independently, turning, say, 8675309
into 9
and 867530
, and using the 9
to increase our total, again incrementing our count, and recurring with 867530
and these new values. The recursion bottoms out the same way, and we return the same quotient.
A final sample is not recursive, showing an interesting running calculation for our average, not explicitly storing a total
anywhere, and deriving the count
from the running index:
const avgOfDigits = (n) => String (n) .split ('') .reduce (
(avg, digit, idx) => (avg * idx + Number (digit)) / (idx + 1),
0
)
console .log (avgOfDigits (8675309)) //=> 5.428571428571429
Here we keep a running average, which we adjust using the index as a count of digits seen so far. The efficiency will suffer because on each iteration, we are not just adding two numbers but also performing a multiplication and a division. And it offers little over other simpler versions, but a variant of it could be used successfully with some sort of scan
function.
I didn't explain what I meant by that scan
comment. The idea is simple enough. scan
is a function that acts like reduce
but keeps all the partially accumulated values. So scan ((a, b) => a + b)) (0) ([1, 2, 3, 4, 5]) //=> [1, 3, 6, 10, 15]
, which is [(1), (1 + 2), (1 + 2 + 3), (1 + 2 + 3 + 4), (1 + 2 + 3 + 4 + 5)]
.
It's easy enough to write a scan function, and with one of those, this style of averaging may become more useful. For example,
const scan = (fn) => (init) => (xs) =>
xs .reduce ((a, x, i) => a .concat (fn (i == 0 ? init : a [i - 1], x, i)), [])
const digitAvgs = scan (
(avg, digit, idx) => (avg * idx + Number (digit)) / (idx + 1),
) (0)
console .log (digitAvgs ([8, 6, 7, 5, 3, 0, 9]))
Upvotes: 0
Reputation: 405955
You were close. Your implementation is setting sum
equal to the recursive function, so that function is never getting called inside averageOfDigits
. I think the confusing part was referring to the same function by two different names.
Here I define the sum
function once, then call it twice. First is the internal recursive call, and second is in the return
statement.
function averageOfDigits(number) {
// Make the whole number into a string first to get the individual digits
let arrOfStr = number.toString().split('');
// Convert this array into integers
let arrOfNum = arrOfStr.map(parseFloat)
// Find sum of these digits using recursion
function sum(arrOfNum) {
if (arrOfNum.length === 1) {
// base case reached
return arrOfNum[0];
} else {
// return first digit + recursive call
return arrOfNum.pop() + sum(arrOfNum);
}
}
return sum(arrOfNum);
}
console.log(averageOfDigits(999))
You can finish off the averageOfDigits
function by replacing the return
statement with your own code. Right now it just returns the sum.
Upvotes: 2
Reputation: 17360
It's missing the initial call to the recursive function.
Hint:
return (function sum(arr) {
if (arr.length === 1) {
return arr[0]
} else {
return arr.pop() + sum(arr)
}
}(arrOfNum))
Upvotes: 1