Lodashを使用してJavaScript配列をチャンクに分割する


83

JavaScript配列をnサイズのチャンクに分割する必要があります。

例:この配列が与えられた

["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"]

およびn4に等しい、出力は次のようになります。

[ ["a1", "a2", "a3", "a4"],
  ["a5", "a6", "a7", "a8"],
  ["a9", "a10", "a11", "a12"],
  ["a13"]
]

私はこの問題の純粋なJavaScriptソリューションを知っていますが、すでにLodashを使用しているので、Lodashがこれに対してより良いソリューションを提供するかどうか疑問に思っています。

編集:

アンダースコアソリューションがどれだけ遅いかを確認するために、jsPerfテストを作成しました。

回答:


125

lodashのチャンクを見てくださいhttps://lodash.com/docs#chunk

const data = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"];
const chunks = _.chunk(data, 3);
console.log(chunks);
// [
//  ["a1", "a2", "a3"],
//  ["a4", "a5", "a6"],
//  ["a7", "a8", "a9"],
//  ["a10", "a11", "a12"],
//  ["a13"]
// ]
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>


lodashとアンダースコアの両方に下位互換性のあるAPIがあると便利です
Jonno_FTW 2016年

@ジョナそれは本当です。以前の回答はもはや最良の回答ではないため、読者のために受け入れられた回答を更新しました:)
Cesar Canassa 2017年

90

アンダースコアベースのソリューションの場合は、次のことを試してください。

var data = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"];
var n = 3;
var lists = _.groupBy(data, function(element, index){
  return Math.floor(index/n);
});
lists = _.toArray(lists); //Added this to convert the returned object to an array.
console.log(lists);

チェーンラッパーメソッドを使用すると、次のように2つのステートメントを組み合わせることができます。

var data = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"];
var n = 3;
var lists = _.chain(data).groupBy(function(element, index){
  return Math.floor(index/n);
}).toArray()
.value();

1
奇妙なことに、Underscoreは配列ではなくgroupBy オブジェクトを返します。ディールブレーカーではなく、基本的に同じ機能が得られますが、セマンティクスが少し変わっています。編集:ああ、それは連鎖性を維持するためにそれを行います。まだ面白い。
ジョーダンランニング

@Cesar Canassa:そのコードを読む将来の開発者のために、それを頻繁に使用する場合はカスタムライブラリに関数として配置するか、使用しない場合はコメントすることを検討してください:)
Briguy37

@ジョーダン:気づかなかった。オブジェクトを配列に変換するように回答を編集しました。
チャンドゥ2011

私はアンダースコアを最も得意とすること(そしてOPがアンダースコアベースのソリューションを求めたのでが不当ではない)と機能的なソリューションのためにすべてを使用していますが、このソリューションは大量のオーバーヘッドをもたらすようです。@ ajax33321が指摘しているようspliceに、ループ内はまだ3ライナーであり、私が推測しているように、はるかにパフォーマンスが高くなっています。配列が短い場合はおそらく問題ではありませんが、数百または数千のアイテムを処理している場合は、そのパフォーマンスに注意してください。
ジョーダンランニング

1
これはもはや最善の解決策ではありません。代わりにchunk()を使用してください
Jonah

4

おそらくより単純な式:

const coll = [ "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9" ];
const n = 2;
const chunks = _.range(coll.length / n).map(i => coll.slice(i * n, (i + 1) * n));
console.log(chunks);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>


1
何よりも簡単ですか?答えは独立している必要があります。
ネイサンタギー2015年

4

アンダースコアは、バージョン1.9.0以降、ネイティブで_.chunk()をサポートします。

const data = ["a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", "a11", "a12", "a13"];
const chunks = _.chunk(data, 4);
console.log(chunks);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore.js"></script>


1

これを試してみてください(たとえば、各サブ配列のコンテナになるアイテムの量に基づいて配列を分割する場合):

function chunk(arr, start, amount){
    var result = [], 
        i, 
        start = start || 0, 
        amount = amount || 500, 
        len = arr.length;

    do {
        //console.log('appending ', start, '-', start + amount, 'of ', len, '.');
        result.push(arr.slice(start, start+amount));
        start += amount;

    } while (start< len);

    return result;
};

そしてあなたの場合の使用:

var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],
    chunked = chunk(arr, 0, Math.floor(arr.length/3)); //to get 4 nested arrays

console.log(chunked);

および別のケース:

var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],
    chunked = chunk(arr, 0, 3); // to get 6 nested arrays each containing maximum of 3 items

console.log(chunked);

そのstartパラメータは実際には実用的ではありません。あなたは通常それを渡したくないでしょう。ただし、常にチャンクサイズを指定する必要があります。これらの2つのパラメーターを交換することをお勧めします。
ベルギ2015

なぜこれがdo whileループなのですか?誰も空のチャンクを取得したくありません。
ベルギ2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.