Functionally breaking an integer into pieces

Consider the problem of decomposing milliseconds into readable units of time. Imagine you had a function that did this

> breakupMillis(100000000)
Array [ 0, 40, 46, 3, 1 ]

means that 100 million milliseconds is exactly 1 day, 3 hours, 46 minutes and 40 seconds.

The function can be generalized by adopting an array of modules, like this

> breakup(100000000, [1000, 60, 60, 24]) 
Array [ 0, 40, 46, 3, 1 ]

This function can be used (hypothetically) for other things:

> breakup(1000, [8, 8, 8]) 
Array [ 0, 5, 7, 1 ]

means 1000 in decimal is 01750 in octal.

Here is what I wrote for this:

const breakup = (n, l) => l.map(p => 
    { const q = n % p; n = (n - q) / p; return q; }).concat(n);

This feature is beautiful, it is even referentially transparent, but I have two completely aesthetic complaints.

  • map. This seems to work for reduce, although I do not understand how to do it.
  • rewriting a variable n. I generally do not like to use var; using a secret varmakes it worse.

. , ( )? map , ​​ .

+4
3

, quotrem - n d, [<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 ]
Hide result

, (isEmpty, head tail)

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 ]
Hide result
+2

reduce, , .

, , reduce: -)

( ): , , . ES6 :

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

push . , ( concat), , , , . , JS - scan .

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);
}

(, , ..) .

+1

:

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]));
Hide result
0

Source: https://habr.com/ru/post/1672845/


All Articles