Skip to content Skip to sidebar Skip to footer

Breaking An Integer Up Into Chunks, Functionally

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 ] meanin

Solution 1:

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>]

constquotrem = (n, d) => [n / d >> 0, n % d]

constbreakup = (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

constisEmpty = xs => xs.length === 0consthead = xs => xs[0]
consttail = xs => xs.slice(1)
constquotrem = (n, d) => [n / d >> 0, n % d]

constbreakup = (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 ]

Solution 2:

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:

functionbreakup(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

functionbreakup(n, units) {
    const [rest, res] = units.mapAccum((n, u) => {
        const q = n % u;
        return [q, (n-q) / u];
    }, [n, units]);
    return [...res, rest];
}
functionbreakup(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.

Solution 3:

I would suggest this code:

constbreakup = (n, l) => 
    l.reduce( ([n, ...res], p) => ([(n - n % p) / p, n % p, ...res]), [n])
     .reverse();

// Demo callconsole.log(breakup(100000000, [1000, 60, 60, 24]));

Post a Comment for "Breaking An Integer Up Into Chunks, Functionally"