JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptでレコードを集計する方法|reduceを使った実装例


ここでは、複数の人物が行った取引の情報を格納した、オブジェクトの配列を例に考えてみましょう。

const transactions = [{
    name: 'Rakesh',
    amount: 1500
}, {
    name: 'Rajesh',
    amount: 1200
}, {
    name: 'Ramesh',
    amount: 1750
}, {
    name: 'Rakesh',
    amount: 2100
}, {
    name: 'Mukesh',
    amount: 1100
}, {
    name: 'Rajesh',
    amount: 1950
}, {
    name: 'Mukesh',
    amount: 1235
}, {
    name: 'Ramesh',
    amount: 2000
}];

今回求められているのは、この配列を受け取り、同じ人物ごとに取引金額を合計し、人物ごとのオブジェクトとして返す関数です。つまり「name」をキーにしてレコードをグループ化し、amount の合計値を算出する処理になります。

それでは、実際のコードを見ていきましょう。

実装例

const transactions = [{
    name: 'Rakesh',
    amount: 1500
}, {
    name: 'Rajesh',
    amount: 1200
}, {
    name: 'Ramesh',
    amount: 1750
}, {
    name: 'Rakesh',
    amount: 2100
}, {
    name: 'Mukesh',
    amount: 1100
}, {
    name: 'Rajesh',
    amount: 1950
}, {
    name: 'Mukesh',
    amount: 1235
}, {
    name: 'Ramesh',
    amount: 2000
}];

const aggregateArray = arr => {
    return arr.reduce((acc, val) => {
        const index = acc.findIndex(obj => obj.name === val.name);
        if(index !== -1){
            acc[index].amount += val.amount;
        }else{
            acc.push({
                name: val.name,
                amount: val.amount
            });
        };
        return acc;
    }, []);
};
console.log(aggregateArray(transactions));

コードの解説

この関数では、Array.prototype.reduce() メソッドを中心に処理を組み立てています。reduce は配列の各要素を順番に処理しながら、単一の累積値(ここでは結果となる配列)を組み立てるのに適したメソッドです。

処理の流れは以下の通りです。

  • findIndex() で、累積配列 acc の中に同じ名前(name)を持つオブジェクトが既に存在するかどうかを確認します。
  • 見つかった場合(index !== -1)は、該当オブジェクトの amount に現在の取引額を加算します。
  • 見つからなかった場合は、新しいオブジェクトとして acc に追加(push)します。
  • 最後に acc を返すことで、その値が次の要素の処理へ引き継がれます。

出力結果

上記のコードを実行すると、コンソールには次のように出力されます。

[
    { name: 'Rakesh', amount: 3600 },
    { name: 'Rajesh', amount: 3150 },
    { name: 'Ramesh', amount: 3750 },
    { name: 'Mukesh', amount: 2335 }
]

たとえば Rakesh の場合、1500 + 2100 = 3600 となっており、同一人物のレコードが正しく集計できていることがわかります。

補足:データ量が多い場合の代替手法

findIndex() を使う方法はシンプルで分かりやすい反面、要素数が増えると計算量が O(n²) に近づき、パフォーマンスが低下する可能性があります。大量のデータを扱う場合は、Map をキー管理に使うことで O(n) まで改善できます。

const aggregateWithMap = arr => {
    const map = new Map();
    for (const { name, amount } of arr) {
        map.set(name, (map.get(name) || 0) + amount);
    }
    return Array.from(map, ([name, amount]) => ({ name, amount }));
};

console.log(aggregateWithMap(transactions));
// 結果は上記と同様になります

用途やデータサイズに応じて、両者の方法を使い分けるとよいでしょう。

  1. JavaScriptのみで各li要素に個別のクラス名を追加する方法

    JavaScriptでli要素にクラスを追加するには、forEach()とclassList.add()を組み合わせて使用します。jQueryなどのライブラリに頼らず、純粋なJavaScript(バニラJS)だけで各要素に個別のクラスを付与できるのがポイントです。基本的な考え方querySelectorAll()で対象の要素をすべて取得し、forEach()で1つずつループ処理を行います。ループのインデックス番号(i)を条件分岐に使うことで、特定の要素だけに異なるクラスを追加することも可能です。サンプルコード以下がそのコードです −<!DOCTYPE html> <

  2. JavaScriptでフラットなオブジェクト配列をツリー構造に変換する方法

    はじめにWeb開発では、カテゴリ一覧やフォルダ構成、組織図など、階層構造をもつデータを画面に表示したい場面がよくあります。一方で、データベースやAPIから取得したデータは、idとparentIdを持つフラット(一次元)な配列として渡されることがほとんどです。本記事では、こうしたフラットな配列をもとに、子要素を親オブジェクトへリンクさせたツリー構造を組み立て、ネストされたリスト形式で画面に表示するまでの手順を、HTML・CSSのコード付きでわかりやすく解説します。元データとなるフラットな配列まず、変換対象となるデータを確認しましょう。各オブジェクトは、自身の一意な識別子であるid、表示名のnam