I have a function that returns the LCM of a range of numbers. It works great, but this has a function inside of a function inside of a function. My question is why can I not simplify the nested smallestCommon() by removing scm() from inside of it? Why does this particular solution need this if else functionality so deeply nested?
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
var candidate = max;
var smallestCommon = function(low, high) {
// inner function to use 'high' variable
function scm(l, h) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high);
}
}
return scm(low, high);
};
for (var i = min; i <= max; i += 1) {
candidate = smallestCommon(i, candidate);
}
return candidate;
}
smallestCommons([5, 1]); // should return 60
smallestCommons([1, 13]); // should return 360360
smallestCommons([23, 18]); //should return 6056820
Having inner functions isn't necessarily bad. Sometimes you want to reduce some local duplication, but don't want to also create a new top-level function. Used carefully, they can clean up code.
In your particular case though, it isn't necessary to have it nested. You can just pass in the high variable as a third parameter:
function scm(l, h, high) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high, high);
}
}
function smallestCommon (low, high) {
return scm(low, high, high);
}
This is actually a fairly common pattern when dealing with recursion: have a recursive function, and a helper function that simplifies calling the recursive function. In functional languages where recursion is common though, it's actually commonplace to have a local recursive function like you had originally (often called something like go).
And it's a shame that JS doesn't have a range function. smallestCommons is basically just a reduction over the range [min,max]. Between the lack of range function and smallestCommon having it's arguments in the wrong order though, converting your code to use reduce unfortunately got a little bulky:
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
return Array.from(new Array(max - min), (x,i) => i + min)
.reduce((acc, i) => smallestCommon(i, acc), max);
}
I'll suggest breaking this down into smaller parts. Instead of one function that's complicated and difficult to debug, you'll have lots of functions that are easy to write and debug. Smaller functions are easier to test and reuse in other parts of your program too -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
console.log
( lcm (1, 5) // 5
, lcm (3, 4) // 12
, lcm (23, 18) // 414
)
Now we have minmax. Unique to this implementation is that it finds the min and the max using only a single traversal of the input array -
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...rest ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( rest
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
console.log
( minmax ([ 3, 4, 2, 5, 1 ]) // [ 1, 5 ]
, minmax ([ 1, 5 ]) // [ 1, 5 ]
, minmax ([ 5, 1 ]) // [ 1, 5 ]
, minmax ([ 9 ]) // [ 9, 9 ]
, minmax ([]) // [ Infinity, -Infinity ]
)
By default minmax returns a list of the min and max values. We can plug the min and max directly into a range function, which might be more useful to us, as we'll see later -
const range = (m, n) =>
m > n
? []
: [ m, ... range (m + 1, n ) ]
console.log
( minmax ([ 3, 4, 2, 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 1, 5 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 9 ], range) // [ 9 ]
, minmax ([], range) // []
)
Now that we can find the min and max of the input, create a range between the two, all that's left is calculating the lcm of the values in the range. Taking many values and reducing them to a single value is done with .reduce -
console.log
( minmax ([1, 5], range) .reduce (lcm, 1) // 60
, minmax ([5, 1], range) .reduce (lcm, 1) // 60
)
Wrap that up in a function and we're done -
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
Verify the result in your own browser below -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...xs ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( xs
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
const range = (m, n) =>
m > n
? []
: [ m, ... range (m + 1, n ) ]
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
extra
Above, minmax is defined using continuation passing style. We save extra computation by passing range as the specified continuation (then). However, we can call minmax without specifying a continuation and spread (...) the intermediate value to range. Either program might make more sense to you. The result is the same -
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
same pig, different farm
smallestCommons is basically just a reduction over the range [min,max] - #Carcigenicate
Hopefully it helps to see the same result from multiple approaches :D
sourface
Some people will despise the above implementation of minmax regardless of its elegance and flexibility. Now that we maybe understand reducing a little better, we can show how minmax might be better implemented using direct style -
const minmax = xs =>
xs .reduce
( ([ min, max ], x) =>
[ Math.min (min, x)
, Math.max (max, x)
]
, [ Infinity, -Infinity ]
)
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1) // direct style now required here
You can unnest it, if you rewrite the inner functions in such a way, that they don't reference variables in their outer scope.
function scm(l, h, step) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + h, step);
}
}
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
return scm(min, max, max);
}
It might blow your stack though, but that's a different problem. If you get a RangeError, you have to rewrite scm to be loop based instead of recursive.
Related
In the game idle heroes, demon bells can be level 1,2,3,4. A level 4 is made of 4 level 1, a level 3 is made of 3 level 1 and so on.
I want to find all arrangements of db given a fixed number. I made this recursive algorithm in javascript:
Closer with a more simplified approach:
function findDB(numDB, arr) {
console.log("findDB"+numDB);
if (numDB == 1) {
console.log("HERE2");
return 1;
} else {
for (let i = 1; i < numDB; i++) {
console.log("FOR"+i);
console.log("COND" +(numDB + (numDB-i)));
if((numDB + (numDB-i)) > numDB+1)
continue;
arr= arr.concat([numDB,[i,findDB(numDB - i, arr)]]);
}
return arr;
}
}
var final = []
var y = findDB(3, final);
console.log(JSON.stringify(y));
Output:
findDB(2) CORRECT!
findDB2
FOR1
COND3
findDB1
HERE2
[2,[1,1]]
FindDB(3) is missing 1,1,1,
findDB3
FOR1
COND5
FOR2
COND4
findDB1
HERE2
[3,[2,1]]
here is intended output for input 1 through 6 (algo needs to scale for any number input)
/1/ (1)
/2/ (2),
(1,1)
/3/ (3),
(2,1),
(1,1,1)
/4/ (4),
(3,1),
(2,2),(2,1,1),
(1,1,1,1)
/5/ (4,1),
(3,2),(3,1,1),
(2,2,1),(2,1,1,1),
(1,1,1,1,1)
/6/ (4,2),(4,1,1),
(3,3),(3,2,1),(3,1,1,1),
(2,2,2),(2,2,1,1),(2,1,1,1,1)
(1,1,1,1,1,1)
This is called the partitions of a number, and is a well-known problem. I'm sure computer scientists have more efficient algorithms than this, but a naive recursive version might look like this:
const partitions = (n, m = n) =>
m > n
? partitions (n, n)
: m == 1
? [Array (n) .fill (1)]
: m < 1
? [[]]
: [
... partitions (n - m, m) .map (p => [m, ...p]),
... partitions (n, m - 1)
];
[1, 2, 3, 4, 5, 6] .forEach ((n) => console .log (`${n}: ${JSON .stringify (partitions (n))}`))
And if you're worried about the default parameter (there sometimes are good reasons to worry), then you can just make this a helper function and wrap it in a public function like this:
const _partitions = (n, m) =>
m > n
? _partitions (n, n)
: m == 1
? [Array (n) .fill (1)]
: m < 1
? [[]]
: [
... _partitions (n - m, m) .map (p => [m, ...p]),
... _partitions (n, m - 1)
];
const partitions = (n) => _partitions (n, n);
[1, 2, 3, 4, 5, 6] .forEach ((n) => console .log (`${n}: ${JSON .stringify (partitions (n))}`))
in either case, n is the integer we're summing to, and m is the maximum integer we can use. If m is too large, we simply call again with an appropriate m. If it equals 1, then we can only have an array of n 1's. If m reaches zero, then we have only the empty partition. Finally, we have two recursive cases to combine: When we choose to use that maximum number, we recur with the remainder and that maximum, prepending the maximum to each result. And when we don't use the maximum, we recur with the same target value and a decremented maximum.
I feel as though this has too many cases, but I don't see immediately how to combine them.
The time is exponential, and will be in any case, because the result is exponential in the size of n. If we added memoization, we could really speed this up, but I leave that as an exercise.
Update
I was bothered by those extra cases, and found an Erlang answer that showed a simpler version. Converted to JS, it might look like this:
const countdown = (n) => n > 0 ? [n , ...countdown (n - 1)] : []
const _partitions = (n, m) =>
n < 0
? []
: n == 0
? [[]]
: countdown (m) .flatMap (x => _partitions (n - x, x) .map (p => [x, ...p]))
We have a quick helper, countdown to turn, say 5 into [5, 4, 3, 2, 1]. The main function has two base cases, an empty result if n is negative and a result containing only the empty partition if n is zero. Otherwise, we countdown the possibilities for the maximum value in a single partition, and recur on the partitions for the target less than this new maximum, adding the maximum value to the front of each.
This should have similar performance characteristics as the above, but it somewhat simpler.
Here is a recursive function that produces the results you want. It attempts to break down the input (numDB) into parts up to the maximum number (maxDB, which defaults to 4). It does this by taking the numbers from numDB down to 1 and adding all the possible results from a recursive call to that number, noting that the value of maxDB has to change to be no more than the first number.
const findDB = function(numDB, maxDB = 4) {
if (numDB == 0) return [ [] ];
let result = [];
let thisDB = Math.min(numDB, maxDB);
for (let i = thisDB; i > 0; i--) {
findDB(numDB - i, Math.min(i, thisDB)).forEach(n => {
result.push([i].concat(n));
});
}
return result;
}
;
[6, 5, 4, 3, 2, 1].forEach((i) => console.log(JSON.stringify(findDB(i))))
.as-console-wrapper {
min-height: 100% !important;
}
I've written the above function in the style in your question, with the use of various ES6 Array methods it can be simplified:
const DBlist = (n) => [...Array(n).keys()].map(k => n - k)
const findDB = (numDB, maxDB = 4) => {
if (numDB == 0) return [ [] ];
const thisDB = Math.min(numDB, maxDB);
return DBlist(thisDB).flatMap((i) => findDB(numDB - i, Math.min(i, thisDB)).map(a => [i, ...a]))
}
DBlist(6).forEach((n) => console.log(JSON.stringify(findDB(n))))
.as-console-wrapper {
min-height: 100% !important;
}
I need to convert this function using the functional programming paradigm but I don't know how, I can use reducer or map creating an array but I don't know how to implement it, i can't use divide operator, loop or recursion;
function divide(dividend, divisor) {
var result = 0;
while (dividend >= divisor) {
dividend -= divisor;
result++;
}
return result;
}
console.log(divide(100, 2));
The way to do it declaratively is with a recursive function....
const divide = (t, b, depth = 0) => t < b ? depth : divide(t-b, b, depth+1);
console.log(`150 / 3 = ${divide(150, 3)}`);
console.log(`24 / 3 = ${divide(24, 3)}`);
console.log(`4 / 3 = ${divide(4, 3)}`);
I'm a bit puzzled by the requirements. My understanding is that loops or recursion aren't prohibited in functional programming. Assuming this is an exercise (it has to be) then here's another way to look at it:
To solve a / b you can count how many b you can fit in a. So for example:
10 / 2 -> [2, 2, 2, 2, 2] -> 5
or:
+2 +2 +2 +2 (map)
10 / 2 -> [2, 4, 6, 8, 10] -> 5
^ ^^
(x) (pred)
So we can unfold the divisor into a list of sums of itself:
const unfold = (pred, map, x) => {
const ys = [];
for (let y = x; pred(y); y = map(y)) ys.push(y);
return ys;
}
unfold(x => x <= 10, x => x + 2, 2);
//=> [2, 4, 6, 8, 10]
Now we can implement divide with unfold and return the length of the list:
const divide = (a, b) =>
unfold(x => x <= a, x => x + b, b)
.length;
divide(10, 2);
//=> 5
My Final solution is this:
const adition = (a, b) => a + b;
const subtraction = (a, b) => a - b;
const multiplication = (a, b) => {
return b >= 0 ? [...Array(b)].reduce((acc) => adition(acc, a), 0) : [...Array(a)].reduce((acc) => adition(acc, b), 0);
};
const division = (a, b) => {
return a === 0 || b === 0 ? 'Error' : b > 1 ? [...Array(a).keys()].reduce((acc, num) => multiplication(num, b) <= a ? adition(acc, 1) : acc, -1) : a;
};
What is the best way to implement a function that takes three arguments
smallest length of combinations
highest length of combinations
array of values
and returns all combinations of length l (arg1 <= l <= arg2). E.g.
getComb (2, 2, [1, 2, 3]) === [[1,2], [2,3], [3,1]]
getComb (0, 3, [1, 2, 3]) === [[],[1],[2],[3],[1,2],[2,3],[3,1],[1,2,3]]
(=== is defined here as deep equals without respect to order (almost set equality for both depths of the array) Also duplicate values should be ignored (e.g. getComb(a, b, [x,x,y]) === getComb(a, b, [x,y]) for all a,
b, x, y)
Then a fn to get all combinations can be implemented:
getAllComb = arr => getComb (0, arr.length, arr)
Thanks!
Here's another recursive solution, structured slightly differently from the answer by Nina Scholz. It has a function to choose exactly n elements from the list, and then uses that in the main function, which calls it for each value from min to max:
const choose = (n, xs) =>
n < 1 || n > xs .length
? []
: n == 1
? [...xs .map (x => [x])]
: [
...choose (n - 1, xs .slice (1)) .map (ys => [xs [0], ...ys]),
...choose (n , xs .slice (1))
]
const getCombs = (min, max, xs) =>
xs .length == 0 || min > max
? []
: [...choose (min, xs), ...getCombs (min + 1, max, xs)]
console .log (
getCombs (0, 3, [1, 2, 3]),
getCombs (2, 2, [1, 2, 3])
)
Here getCombs is the main function, and should be fairly clear, just concatenating the result of choose (min, xs) with the result of the recursive call to getCombs (min + 1, max, xs). choose is a nicely reusable function which operates on a double recursion, the first one selecting all those combinations which use the initial element and the second all those that don't.
This doesn't quite match Nina's solution, as it ignores the empty list when min is zero. If you want one that includes the empty list, you could change choose to the (slightly uglier, IMHO) version:
const choose = (n, xs) =>
n < 1 || n > xs .length
? [[]]
: [
...choose (n - 1, xs .slice (1)) .map (ys => [xs [0], ...ys]),
...(n + 1 > xs .length ? [] : choose (n , xs .slice (1)))
]
one way to implement getComb is :
[1,2,3].reduce( (acc, v, i, original) =>
acc.concat(original.slice(i+1).map( w => [w, v] )),
[]);
You could take a recursive approach.
function getComb(min, max, array) {
function iter(left, right = [], push = true) {
if (push && min <= right.length && right.length <= max) result.push(right);
if (!left.length) return;
iter(left.slice(1), [...right, left[0]]);
iter(left.slice(1), right, false);
}
var result = [];
iter(array);
return result;
}
console.log(getComb(2, 2, [1, 2, 3]));
console.log(getComb(0, 3, [1, 2, 3]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ok I have a partial solution (for a = 1, b = arr.length):
const list = R.unapply (R.identity)
const xproduct = arr => R.apply (R.liftN (arr.length) (list)) (arr)
const getPerm = arr => xproduct (R.repeat (arr) (arr.length))
const getComb = arr => R.uniq (R.map (R.uniq) (getPerm (arr)))
getComb([1,2,3]) === [[1],[2],[3],[1,2],[2,3],[3,1],[1,2,3]]
There's got to be something better ;)
Here's a solution (atleast to getAllComb) that I'm kinda proud of :) There's a lot of stuff, but most of it is boilerplate
Inspired by bitstrings
// Generic helper functions
const appendIfNotFalse = fn => (acc, val) => R.ifElse (R.equals (false)) (R.always (acc)) (R.flip (R.append) (acc)) (fn (acc, val))
const mapAndFilter = fn => arr => R.reduce (appendIfNotFalse (fn)) ([]) (arr)
// My helper fn
const has1InBitstring = n => idx => (n & 2 ** idx) > 0
// Soltuion
const indices = arr => key => mapAndFilter ((_, j) => has1InBitstring (key) (j) ? j : false) (R.range (0) (arr.length))
const getAllComb = arr => R.times (i => R.props (indices (arr) (i)) (arr)) (2 ** arr.length)
// Example
getAllComb ([1,2,3]) === [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
This question already has answers here:
Finding difference between consecutive numbers in an array in javascript
(4 answers)
Closed 1 year ago.
I have a list of numbers, say numbers = [3,7,9,10] and I want to have a list
containing the differences between neighbor elements - which has to have one
less element - in the given case diffs = [4,2,1]
Of course I could create a new list go through the input list and compile my
result manually.
I'm looking for an elegant/functional (not to say pythonic) way to do this.
In Python you would write [j-i for i, j in zip(t[:-1], t[1:])] or use numpy
for this.
Is there a reduce()/list comprehension approach in JavaScript, too?
You could slice and map the difference.
var numbers = [3, 7, 9, 10],
result = numbers.slice(1).map((v, i) => v - numbers[i]);
console.log(result);
A reversed approach, with a later slicing.
var numbers = [3, 7, 9, 10],
result = numbers.map((b, i, { [i - 1]: a }) => b - a).slice(1);
console.log(result);
You could do this using reduce method
const numbers = [3, 7, 9, 10]
const res = numbers.reduce((r, e, i, a) => i ? r.concat(e - a[i - 1]) : r, []);
console.log(res)
You could also pop after map:
var numbers = [3, 7, 9, 10],
result = numbers.map((v, i) => numbers[i+1]-v);
result.pop()
console.log(result);
you can use map and slice
const numbers = [3, 7, 9, 10, 11, 13];
const res = numbers.map((num, index) => numbers[index + 1] - num).slice(0, -1);
console.log(res)
You can use destructuring assignment and recursion -
const diff = ([ a, b, ...more ]) =>
b === undefined
? []
: [ b - a, ...diff ([ b, ...more ]) ]
console .log (diff ([ 3, 7, 9, 10 ]))
// [ 4, 2, 1 ]
console .log (diff ([ 3 ]))
// []
console .log (diff ([]))
// []
Or skip some intermediate values by using an index -
const diff = (a = [], i = 1) =>
i >= a.length
? []
: [ a[i] - a[i - 1], ...diff (a, i + 1) ]
console .log (diff ([ 3, 7, 9, 10 ]))
// [ 4, 2, 1 ]
console .log (diff ([ 3 ]))
// []
console .log (diff ([]))
// []
If needed, make it stack-safe using loop and recur. This one runs really fast, too -
const recur = (...values) =>
({ recur, values })
const loop = f =>
{ let r = f ()
while (r && r.recur === recur)
r = f (...r.values)
return r
}
const push = (a = [], v) =>
( a .push (v)
, a
)
const diff = (a = []) =>
loop
( ( i = 1
, r = []
) =>
i >= a.length
? r
: recur
( i + 1
, push (r, a[i] - a[i - 1])
)
)
console .log (diff ([ 3, 7, 9, 10 ]))
// [ 4, 2, 1 ]
console .log (diff ([ 3 ]))
// []
console .log (diff ([]))
// []
You can slice (0 as a start, -1 to skip the last item) and map so to generate the differences between an element and its successor in the sequence:
const items = [3,7,9,10];
console.log(items.slice(0,-1).map((e,i)=>items[i+1]-e))
Consider the problem of decomposing milliseconds into readable time units. Imagine you had a function that did that
> breakupMillis(100000000)
Array [ 0, 40, 46, 3, 1 ]
meaning that 100 million milliseconds is 1 day, 3 hours, 46 minutes, and 40 seconds, exactly.
The function could be generalized by accepting an array of moduli, like this
> breakup(100000000, [1000, 60, 60, 24])
Array [ 0, 40, 46, 3, 1 ]
That function could be used (hypothetically) for other things:
> breakup(1000, [8, 8, 8])
Array [ 0, 5, 7, 1 ]
meaning that 1000 in decimal is 01750 in octal.
Here is the function I wrote to do this:
const breakup = (n, l) => l.map(p =>
{ const q = n % p; n = (n - q) / p; return q; }).concat(n);
This function is fine, it's even referentially transparent, but I have two, entirely esthetic, complaints.
the map. This feels like a job for reduce, though I don't see how.
rewriting the variable n. I don't like to use var at all; using a secret var makes it worse.
My question is only about the second. How do I re-write the function so it uses no variable (that actually vary)? If the map disappears, I'll take that as gravy.
Here's another way you can do it using a recursive procedure and a little helper quotrem – which given a numerator n, and a denominator d, returns [<quotient>, <remainder>]
const quotrem = (n, d) => [n / d >> 0, n % d]
const breakup = (n, [x,...xs]) => {
if (x === undefined) {
return [n]
}
else {
let [q, r] = quotrem(n, x)
return [r, ...breakup(q, xs)]
}
}
console.log(breakup(1000, [8, 8, 8]))
// [ 0, 5, 7, 1 ]
console.log(breakup(100000000, [1000, 60, 60, 24]))
// [ 0, 40, 46, 3, 1 ]
If you're not particularly comfortable with the destructured array, you can add a few more helpers (isEmpty, head, and tail) to interact with the array in a more explicit way
const isEmpty = xs => xs.length === 0
const head = xs => xs[0]
const tail = xs => xs.slice(1)
const quotrem = (n, d) => [n / d >> 0, n % d]
const breakup = (n, xs) => {
if (isEmpty(xs)) {
return [n]
}
else {
let [q, r] = quotrem(n, head(xs))
return [r, ...breakup(q, tail(xs))]
}
}
console.log(breakup(1000, [8, 8, 8]))
// [ 0, 5, 7, 1 ]
console.log(breakup(100000000, [1000, 60, 60, 24]))
// [ 0, 40, 46, 3, 1 ]
This feels like a job for reduce, though I don't see how.
Everything that iterates an array can be done with reduce :-)
We need to pass two things through (for the accumulator): the number that we still have the break, and the list of results. We can use ES6 destructuring and an array as a tuple:
function breakup(n, units) {
const [n, res] = units.reduce(([n, res], u) => {
const q = n % u;
res.push((n-q) / u);
return [q, res];
}, [n, units]);
return [n, ...res];
}
But that push is still ugly. Not only because it mutates (where we could have used concat as well), but what we really want is a function that abstracts this away. Unfortunately these don't exists in JS - we'd be looking for a scan or mapping accumulation. We could write
function breakup(n, units) {
const [rest, res] = units.mapAccum((n, u) => {
const q = n % u;
return [q, (n-q) / u];
}, [n, units]);
return [...res, rest];
}
function breakup(n, units) {
const mods = units.scan((n, u) => Math.floor(n/u), units);
return mods.map((q, i) => i<units.length ? q % units[i] : q);
}
I'll leave the (functional, efficient, readable, etc) implementation of those as an exercise to the reader.
I would suggest this code:
const breakup = (n, l) =>
l.reduce( ([n, ...res], p) => ([(n - n % p) / p, n % p, ...res]), [n])
.reverse();
// Demo call
console.log(breakup(100000000, [1000, 60, 60, 24]));