2017-03-21 7 views
4

ミリ秒を読み取り可能な時間単位に分解する問題を考慮してください。あなたは整数をチャンクに分割する、機能的に

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

は億ミリ秒は、正確に3時間、46分、40秒、1日であることを意味することをしなかった機能を持っていた想像してみてください。

機能は、他のもののために(仮に)その機能を使用することができる。この

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

のように、弾性係数の配列を受け入れることによって一般化することができます

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

十進数で1000があることを意味します01750を8進数で表します。ここで

が、私はこれを行うために書いた関数である。

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

この機能は、それも参照透明だ、大丈夫ですが、私は2、完全にエステ、不満を持っています。

  • map。これはreduceの仕事のように感じますが、私はどのように見えません。
  • 変数nを書き換えます。私はvarをまったく使用したくありません。 秘密varを使用すると悪化します。

私の質問は約2番目です。変数を使用しないように関数を書き直すにはどうすればよいですか(実際は変わります)? mapが消えたら、私は肉汁としてそれを取る。

+0

を私はちょっとこれはHaskellではコードレビュー – Tschallacka

+0

に属している感じがあります '分割nl = zipでmod l。 scanl div n l' – Bergi

答えて

1

これはreduceの仕事のように感じますが、私はどのように見えません。我々は(アキュムレータ用)を介して2つの事柄を渡す必要があり、配列が

:-) 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またはmapping accumulationを探しています。私たちは書くことができる

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

私はこれらの機能の(機能的、効率的、可読な、その他の)実装を読者に任せます。ここで

2

あなたは再帰的な手順を使用してそれを行うことができます別の方法だと少しヘルパー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 ]

を返します。構造化されていない配列に特に慣れていない場合は、いくつかのヘルパー(isEmptyhead、および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 ]

+0

私は 'arguments [1] .length == 0'をテストし、要素が決して' undefined 'でないことに頼らないでください。 – Bergi

+1

@Bergiはコメントをありがとう - 配列を少しずつ扱う副回答を追加しました^ _^ – naomik

+0

'>> 0'の正確な動作が不思議です。 'Math.floor()'と同じですか? – Malvolio

0

より明示的な方法で:

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

関連する問題