JavaScriptでオブジェクト配列のプロパティ値を科目ごとに合計する方法
はじめに
JavaScriptでは、オブジェクトの配列から特定のプロパティをキーとしてデータをグループ化し、数値プロパティの合計を求めたい場面がよくあります。例えば、学生の科目ごとの点数と人数をまとめたデータから、科目ごとの合計を算出するケースを考えてみましょう。
以下のような、学生の点数データを含むオブジェクトの配列があるとします。
const arr = [
{ subject: 'Maths', marks: '40', noOfStudents: '5' },
{ subject: 'Science', marks: '50', noOfStudents: '16' },
{ subject: 'History', marks: '35', noOfStudents: '23' },
{ subject: 'Science', marks: '65', noOfStudents: '2' },
{ subject: 'Maths', marks: '30', noOfStudents: '12' },
{ subject: 'History', marks: '55', noOfStudents: '20' },
];
この配列には、同じ科目(subject)が複数回出現しています。ここで、次のような要件を満たすJavaScriptの関数を作成します。
- 「subject」プロパティを基準に、重複するエントリを1つにまとめる
- 同一科目の「marks」(点数)と「noOfStudents」(人数)を合計し、1つのオブジェクトに集約する
したがって、上記の配列の場合、期待される出力は次のようになります。
const output = [
{ subject: 'Maths', marks: 70, noOfStudents: 17 },
{ subject: 'Science', marks: 115, noOfStudents: 18 },
{ subject: 'History', marks: 95, noOfStudents: 43 },
];
実装例
この処理は、reduce()メソッドと、科目名を結果配列のインデックスにマッピングするオブジェクト(マップ)を組み合わせることで、効率的に実装できます。
const arr = [
{ subject: 'Maths', marks: '40', noOfStudents: '5' },
{ subject: 'Science', marks: '50', noOfStudents: '16' },
{ subject: 'History', marks: '35', noOfStudents: '23' },
{ subject: 'Science', marks: '65', noOfStudents: '2' },
{ subject: 'Maths', marks: '30', noOfStudents: '12' },
{ subject: 'History', marks: '55', noOfStudents: '20' },
];
const groupBySubject = (arr = []) => {
const map = {};
const res = arr.reduce((acc, val) => {
const { subject, marks, noOfStudents } = val;
const { length: l } = acc;
if (map.hasOwnProperty(subject)) {
// 既存のエントリに値を加算
acc[map[subject]]['marks'] += +marks;
acc[map[subject]]['noOfStudents'] += +noOfStudents;
} else {
// 新しい科目の場合はマップに登録してエントリを追加
map[subject] = l;
acc.push({
subject: subject,
marks: +marks,
noOfStudents: +noOfStudents
});
}
return acc;
}, []);
return res;
};
console.log(groupBySubject(arr));
コードの解説
このコードのポイントは以下の通りです。
- mapオブジェクト:科目名を結果配列内のインデックスに対応付けることで、各科目のオブジェクトの位置を高速に検索できます。
- reduce()メソッド:配列を走査しながら、単一の結果配列を構築します。
- 単項プラス演算子(+):文字列として格納されている「marks」と「noOfStudents」を数値に変換します。
- +=演算子:既存のエントリが見つかった場合、値を上書きするのではなく加算することで、合計値を正しく計算します。ここを「=」にしてしまうと、合計ではなく最後の値で上書きされてしまうので注意が必要です。
出力結果
コンソールに出力される結果は次の通りです。
[
{ subject: 'Maths', marks: 70, noOfStudents: 17 },
{ subject: 'Science', marks: 115, noOfStudents: 18 },
{ subject: 'History', marks: 95, noOfStudents: 43 }
]
このように、重複していた科目ごとに点数と人数が正しく合計され、重複のない配列が得られました。
まとめ
オブジェクト配列のグループ化と合計処理は、集計処理やデータ分析の前処理など、実務でも頻繁に登場するパターンです。reduce()とマップを組み合わせるこの手法を覚えておくと、さまざまな場面で応用できます。
-
JavaScriptでオブジェクトを新しい配列に変換する方法
JavaScriptでは、オブジェクトのプロパティやネストされたデータを取り出し、扱いやすい形で新しい配列にフォーマットできます。本記事では、学校(school)オブジェクトに含まれる生徒情報を、文字列形式の配列へ変換する実践的なコード例を紹介します。 ポイントとなるテクニック このサンプルでは、以下の2つのJavaScript機能を活用しています。 分割代入(Destructuring assignment):オブジェクトから特定のプロパティを簡潔に取り出す構文です。 for...of ループ:配列内の各要素を順番に処理するために使用します。 コード例 <!DOCTYPE html
-
JavaScriptで配列内オブジェクトのプロパティ名を置き換える方法
JavaScriptでオブジェクト配列のプロパティ名を置き換える方法 JavaScriptでは、map()メソッドを活用することで、配列に含まれる各オブジェクトのプロパティ名を別の名前に簡単に置き換えることができます。map()は元の配列を変更せずに新しい配列を生成するため、安全かつ効率的なデータ変換処理に適しています。 以下は、オブジェクト配列のプロパティ名 name を fullName に置き換えるサンプルコードです。 サンプルコード <!DOCTYPE html> <html lang="en"> <head> <meta