JavaScriptで配列内の重複要素をグループ化する方法
JavaScriptでは、配列内に含まれる同じ値の要素を、それぞれ独立したサブ配列にまとめたいケースがあります。例えば、以下のように同じアルファベットが繰り返し含まれる配列を考えてみましょう。
const arr = [
'a','a','a','a','d','e','e','f','h','h','h','i','l','m','n',
'r','s','s','t','u','v','y','y'
];実現したいこと
このような配列を引数として受け取るJavaScript関数を作成します。この関数は、同じ値を持つ要素同士を1つのサブ配列にまとめる必要があります。
上記の配列の場合、期待される出力結果は次のようになります。
const output = [
['a','a','a','a'], ['d'], ['e','e'], ['f'], ['h','h','h'],
['i'], ['l'], ['m'], ['n'], ['r'], ['s','s'], ['t'], ['u'],
['v'], ['y','y']
];実装コード
この処理は、reduce()メソッドとハッシュ(オブジェクト)を組み合わせることで効率的に実装できます。ハッシュを使って各値がすでに出現しているかどうかを記録し、初出の場合は新しいサブ配列を作成し、既出の場合は対応するサブ配列に要素を追加していきます。
const arr = [
'a','a','a','a','d','e','e','f','h','h','h','i','l','m','n',
'r','s','s','t','u','v','y','y'
];
const bringAlong = (arr = []) => {
const hash = {};
return arr.reduce(function(res, e) {
if(hash[e] === undefined)
hash[e] = res.push([e]) - 1;
else
res[hash[e]].push(e);
return res;
}, []);
};
console.log(bringAlong(arr));コードのポイント
hashオブジェクトで、各値がどのサブ配列(インデックス)に属するかを管理しています。res.push([e]) - 1により、新しく作成したサブ配列のインデックスを取得し、ハッシュに登録します。- 2回目以降の出現時には、
res[hash[e]].push(e)で該当するサブ配列へ要素を追加します。
出力結果
コンソールには次のように表示されます。
[
[ 'a', 'a', 'a', 'a' ],
[ 'd' ],
[ 'e', 'e' ],
[ 'f' ],
[ 'h', 'h', 'h' ],
[ 'i' ],
[ 'l' ],
[ 'm' ],
[ 'n' ],
[ 'r' ],
[ 's', 's' ],
[ 't' ],
[ 'u' ],
[ 'v' ],
[ 'y', 'y' ]
]補足:別のアプローチ
モダンなJavaScript環境では、Object.groupBy()やMap.groupBy()(ES2024以降)を使用することで、より簡潔にグループ化を実現できます。ただし、これらは元の順序や連続性に関係なくキーごとにまとめるため、「連続する同一要素」をまとめたい場合は本記事のreduce()を使った方法が適しています。
-
JavaScriptでIDごとにオブジェクトの配列をグループ化する方法
JavaScriptでオブジェクトの配列をidなどの特定のキーごとにグループ化したい場合、reduce()メソッドを使うと簡潔に実装できます。この記事では、どのプロパティにも対応できる汎用的なgroupBy関数を作成し、実際のサンプルコードとともにその仕組みを詳しく解説します。 reduce()によるグループ化の考え方 reduce()は、配列の各要素を順番に処理しながら、1つの累積値(ここではオブジェクト)を組み立てていくメソッドです。各要素からキーの値を取り出し、その値がまだ結果オブジェクトに存在しなければ新しい配列を作成して、そこへ要素を追加していくことでグループ化を実現します。 サ
-
JavaScriptで配列の最後の要素を取得・表示する方法
配列の最後の要素を取得して画面に表示するには、pop()メソッドを利用するのが手軽です。以下に、ボタンをクリックすると配列の最後の要素を表示するサンプルコードを示します。 コード例 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> &