【JavaScript】連続する要素をグループ化して配列を圧縮する方法
はじめに
本記事では、ハイフン(-)で区切られた単語が含まれる文字列から、連続して出現する同じ単語をグループ化し、それぞれの連続出現回数とともにオブジェクトの配列として返す関数をJavaScriptで実装します。
問題の概要
まず、次のように繰り返しの単語がハイフン(-)で区切られて含まれる文字列が与えられます。
const str = 'monday-sunday-tuesday-tuesday-sunday-sunday-monday-monday-monday';
ここでの課題は、各オブジェクトが val と count という2つのプロパティを持つ配列を返す関数を書くことです。val は文字列内の単語(monday、tuesday、sundayなど)、count はその単語の連続出現回数を表します。
上記の文字列の場合、期待される結果は次のようになります。
const arr = [
{
val: 'monday',
count: 1
},
{
val: 'sunday',
count: 1
},
{
val: 'tuesday',
count: 2
},
{
val: 'sunday',
count: 2
},
{
val: 'monday',
count: 3
}
]これは、mondayが1回、続いてsundayが1回、tuesdayが2回、sundayが2回、最後にmondayが3回連続して出現しているためです。
実装のアプローチ
実装の手順は以下の通りです。
String.prototype.split()を使って、文字列をハイフンで分割し配列に変換します。Array.prototype.reduce()メソッドを使って、結果の配列を再帰的に(畳み込みながら)構築していきます。- 直前の要素と現在の単語が一致する場合は
countをインクリメントし、一致しない場合は新しいオブジェクトを追加します。
なお、コード内では acc[l-1]?.val のようにオプショナルチェイニング(?.)を使用しています。これにより、初期状態で空配列の場合でもエラーが発生せず、安全に処理できます。
サンプルコード
以下が完全なコードです。
const str = 'monday-sunday-tuesday-tuesday-sunday-sunday-monday-monday-monday';
const str2 = 'friday-friday-sunday-tuesday-sunday-sunday-monday-thursday-monday';
const compressString = (str) => {
return str.split('-').reduce((acc, val) => {
const { length: l } = acc;
if (acc[l - 1]?.val === val) {
// 直前のグループと同じ単語ならカウントを増やす
acc[l - 1].count++;
return acc;
} else {
// 新しい単語なら新しいグループを作成
return acc.concat({
val,
count: 1
});
}
}, []);
}
console.log(compressString(str));
console.log(compressString(str2));処理の流れを詳しく解説
- split('-'):文字列をハイフンで分割し、
['monday', 'sunday', 'tuesday', ...]のような単語の配列を生成します。 - reduce():初期値として空配列
[]を渡し、各単語を順番に処理します。 - 条件分岐:累積配列
accの最後の要素のvalが現在の単語と一致すればcount++で連続回数を更新。不一致なら{ val, count: 1 }を新たに追加します。
実行結果
上記のコードをコンソールで実行すると、次のような出力が得られます。
[
{ val: 'monday', count: 1 },
{ val: 'sunday', count: 1 },
{ val: 'tuesday', count: 2 },
{ val: 'sunday', count: 2 },
{ val: 'monday', count: 3 }
]
[
{ val: 'friday', count: 2 },
{ val: 'sunday', count: 1 },
{ val: 'tuesday', count: 1 },
{ val: 'sunday', count: 2 },
{ val: 'monday', count: 1 },
{ val: 'thursday', count: 1 },
{ val: 'monday', count: 1 }
]まとめ
このように、split() と reduce() を組み合わせることで、文字列内の連続する同一単語を効率的にグループ化できます。このテクニックは、ログデータの集計や時系列データの圧縮など、さまざまな場面で応用できる汎用的なパターンです。ぜひ実際のプロジェクトでも活用してみてください。
-
JavaScriptで配列内のオブジェクトの数を数える方法
JavaScriptで配列の中に含まれるオブジェクトの数を数えたい場合、Object.prototype.__proto__プロパティを利用する方法があります。このプロパティはオブジェクトのプロトタイプチェーンをたどるもので、要素がプレーンなオブジェクトかどうかを判別する際に役立ちます。仕組みの解説配列の各要素に対してval.__proto__.__proto__が偽(falsy)になるかどうかをチェックします。オブジェクトリテラルの場合、__proto__はObject.prototypeを指し、そのさらに上位の__proto__はnullとなるため条件が真になり、カウントが1つ増えます。一
-
JavaScriptでIDごとにオブジェクトの配列をグループ化する方法
JavaScriptでオブジェクトの配列をidなどの特定のキーごとにグループ化したい場合、reduce()メソッドを使うと簡潔に実装できます。この記事では、どのプロパティにも対応できる汎用的なgroupBy関数を作成し、実際のサンプルコードとともにその仕組みを詳しく解説します。 reduce()によるグループ化の考え方 reduce()は、配列の各要素を順番に処理しながら、1つの累積値(ここではオブジェクト)を組み立てていくメソッドです。各要素からキーの値を取り出し、その値がまだ結果オブジェクトに存在しなければ新しい配列を作成して、そこへ要素を追加していくことでグループ化を実現します。 サ