javascriptでpartition 関数を実装
こんにちは
javascriptでhaskellでいうところのpartition関数を実装してみたのでメモします。
partition関数
全然一般的ではないので説明です。僕がpartition関数って言っているのは、「配列を、その要素に対して真偽を判定する関数により、真なものと偽なものの2つのグループに分ける関数」です。
たとえば以下のように動くものです。
[0,1,2,3,4,5,6,7,8,9].partition(num => num > 4) // => [[5,6,7,8,9],[0,1,2,3,4]] [1,"2",3].partition(item => typeof item === 'string') // => [["2"],[1,3]]
いかにもありそうな関数ですが、探した限りではありませんでした。(altjsでは実装されている場合があるようです)
やっちゃだめみたいですがArrayのprototypeを汚染して関数を定義します。Arrayの他のコールバックを引数に取る関数を参考にしました。
Array.prototype.partition = function(callback, thisArg) { if (this === null) { throw new TypeError('Array.prototype.partition called on null or undefined'); } if (typeof callback !== 'function') { throw new TypeError('callback must be a function'); } var T; if (thisArg) { T = thisArg; } var list = Object(this); var length = list.length >>> 0; var value; var accepted = new Array(); var rejected = new Array(); for(var i = 0; i < length; i++) { value = list[i]; if (callback.call(T, value, i, list)) { accepted.push(value); } else { rejected.push(value); } } return [accepted, rejected]; }; [0,1,2,3,4,5,6,7,8,9].partition(num => num > 4) // => [[5,6,7,8,9],[0,1,2,3,4]] [1,"2",3].partition(item => typeof item === 'string') // => [["2"],[1,3]]
第二引数のthisArg
はArray.prototype.map
の仕様にあったため追記しました。使い道があまりわかりませんが例えば繰り返しの中で副作用を起こさせることができます(ちょっと意味のない例。。。)。
追記(2017/11/29): よく考えるとthisArg
は関数呼ぶ時に呼び元のthis
を渡したりする時に使うためでした。
[1,2,3,4,5].partition(function(num) { this.log(num) ; return num > 2; }, { log(num) { console.log(`${num}を振り分けました`) } });
最後にreduceを使って、配列とコールバックを引数に取る関数として書いてみます。
const partition = (list, callback) => { if (list === null) throw new TypeError('partition called on null or undefined'); if (typeof callback !== 'function') throw new TypeError('callback must be a function'); return list.reduce((state, item) => { if(callback(item)) { state[0].push(item); } else { state[1].push(item); } return state; }, [[],[]]); }; partition([0,1,2,3,4,5,6,7,8,9], num => num > 4) // => [[5,6,7,8,9],[0,1,2,3,4]] partition([1,"2",3], item => typeof item === 'string') // => [["2"],[1,3]]
感想
テストとか書いてしっかり確かめたいですね。小さいものは書いていて楽しいです。