JavaScriptで配列を指定された個数ずつに分割します。
例えば、
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
という配列を3個ずつ分割するのであれば、
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
という配列になります。
実装方針
配列から一部を通り出すのには、
Array.prototype.slice() - JavaScript | MDN
という関数が使えます。
この関数は、開始のインデックスと終わりのインデックスを渡すと、開始のインデックスから終わりのインデックスの1つ前までの部分の配列を返します。
pythonのmylist[begin:end]
、rubyのarray[begin...end]
のような動作をします。
例えば、
const array=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
であれば、
array.slice(3, 6),
は、3、4、5のインデックスを含むので
[4, 5, 6]
という配列が返されます。
また、
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
という配列をこのように3個ずつ分割するのを、
[[1,2,3], [4,5,6], [7,8,9], [10]]
slice()
を使用して書くと、
const result = [ array.slice(0, 3), array.slice(3, 6), array.slice(6, 9), array.slice(9, 10) ]
となります。slice()
の2つめの引数に配列の数より大きな値が指定された場合は、array.length
が指定されたのと同じになりますので、下記のように書き換えても同様の結果になります。最後の要素を、array.slice(9, 10)
からarray.slice(9, 12)
に変更しました。これで各sliceの引数が全て3の倍数となりました。
const result = [ array.slice(0, 3), array.slice(3, 6), array.slice(6, 9), array.slice(9, 12) ]
ところで、最終的な配列のサイズは、
分割する対象の配列を3で割って、端数が出たら切り上げた数です。今回分割する対象の配列の長さは10ですので、10/3=3.333..
これを切り上げて4が最終的に作成される配列の長さです。
JavaScriptで切り上げを行うには、
Math.ceil() - JavaScript | MDN
を使用します。
インデックスを3ずつずらしながら、array.slice()
を、作成する配列の長さぶん繰り返せば、配列を分割することができそうです。
コード
コードをステップバイステップで作成します。
はじめに関数を定義します。引数に分割対象の配列と、いくつずつに分割するか指定します。
const sliceByNumber = (array, number) => { console.log('array', array) console.log('number', number) return array } console.log(sliceByNumber([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3))
実行結果です。疎通確認が完了しました。
array [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] number 3 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
作成する配列のサイズを計算します。
const sliceByNumber = (array, number) => { const length = Math.ceil(array.length / number) console.log('length', length) return array } console.log(sliceByNumber([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3))
実行結果です。作成する配列の長さ"4"が取得できました。
length 4 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
次に、長さ4の配列を作成し、配列の各要素に対してmapを呼び出します。この時、配列のインデックスの数にnumber
を掛けたものを表示します。
const sliceByNumber = (array, number) => { const length = Math.ceil(array.length / number) return new Array(length).fill().map((_, i) => { console.log(`i=${i}, i*number=${i*number}, (i+1)*number=${(i+1)*number}`) return i }) } console.log(sliceByNumber([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3))
Array(n)
とmap()
の間にfill()
を挟む理由については、こちらの記事を参照してください。
実行結果です。Array.slice
に渡す数が取得できました。
i=0, i*number=0, (i+1)*number=3 i=1, i*number=3, (i+1)*number=6 i=2, i*number=6, (i+1)*number=9 i=3, i*number=9, (i+1)*number=12 [0, 1, 2, 3]
最後に、i*number
と(i+1)*number
をArray.slice
に渡せば、欲しい配列が出来上がります。
const sliceByNumber = (array, number) => { const length = Math.ceil(array.length / number) return new Array(length).fill().map((_, i) => array.slice(i * number, (i + 1) * number) ) } console.log(sliceByNumber([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3))
実行結果です。配列が3個ずつに分割されています。最後は要素数が1になっています。
[ [1, 2, 3], [4, 5, 6], [7, 8, 9], [10] ]
array.length
がnumber
で割り切れる例です。長さ10の配列を5個ずつに分割しました。
[ [1, 2, 3, 4, 5], [6, 7, 8, 9, 10] ]
以上でn個ずつ配列を分割することができました。