LINQ

[C#/LINQ] Aggregate()の使い方 – 数値の合計/文字列連結/最大値検索

Aggregate()は、C#のLINQメソッドで、コレクションの要素を累積的に処理するために使用されます。

数値の合計を求める場合、初期値を0にして各要素を加算します。

文字列の連結では、初期値を空文字にして各要素を結合します。

最大値の検索では、初期値を最小値に設定し、各要素と比較して大きい方を選びます。

例えば、numbers.Aggregate(0, (acc, x) => acc + x)で数値の合計を計算できます。

Aggregate()メソッドとは

C#のLINQ(Language Integrated Query)におけるAggregate()メソッドは、コレクション内の要素を累積的に処理するための強力なツールです。

このメソッドは、指定した関数を用いてコレクションの各要素を1つの結果にまとめることができます。

例えば、数値の合計や文字列の連結、最大値の検索など、さまざまな集計処理に利用されます。

Aggregate()メソッドは、初期値を指定することもでき、これにより計算の開始点を柔軟に設定できます。

ラムダ式を使用して、どのように要素を累積するかを定義することができるため、非常に直感的で使いやすいです。

LINQの他のメソッドと組み合わせることで、より複雑なデータ処理を行うことも可能です。

これにより、データの集計や分析を効率的に行うことができます。

Aggregate()の基本構文

Aggregate()のシグネチャ

Aggregate()メソッドの基本的なシグネチャは以下の通りです。

public static TAccumulate Aggregate<TSource, TAccumulate>(
    this IEnumerable<TSource> source,
    TAccumulate seed,
    Func<TAccumulate, TSource, TAccumulate> func
);

このシグネチャでは、TSourceはコレクション内の要素の型、TAccumulateは累積結果の型を示します。

sourceは対象のコレクション、seedは初期値、funcは累積処理を行うための関数です。

初期値を指定する場合としない場合の違い

Aggregate()メソッドでは、初期値を指定することができます。

初期値を指定する場合、最初の累積値はこの初期値となり、コレクションの最初の要素とともに処理が行われます。

初期値を指定しない場合、最初の要素が初期値として使用され、2番目の要素から累積処理が始まります。

初期値指定処理の開始点
指定する初期値 + 最初の要素
指定しない最初の要素から処理開始

ラムダ式を使った累積処理の流れ

Aggregate()メソッドでは、ラムダ式を使用して累積処理を定義します。

ラムダ式は、現在の累積値と次の要素を引数として受け取り、新しい累積値を返します。

以下は、ラムダ式を使った累積処理の流れの例です。

  1. 初期値または最初の要素を設定
  2. コレクションの各要素に対してラムダ式を適用
  3. ラムダ式の結果を次の累積値として使用
  4. 最後の累積値を返す

この流れにより、柔軟で直感的なデータ処理が可能になります。

数値の合計を求める

数値の合計を求める基本例

Aggregate()メソッドを使用して、数値の合計を求める基本的な例を示します。

以下のコードでは、整数のリストを合計しています。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
        
        int sum = numbers.Aggregate((total, next) => total + next);
        
        Console.WriteLine($"合計: {sum}");
    }
}
合計: 15

この例では、リスト内の全ての整数を累積的に加算し、合計を求めています。

初期値を指定しない場合の挙動

初期値を指定しない場合、Aggregate()メソッドはリストの最初の要素を初期値として使用します。

次の要素から累積処理が始まります。

以下のコードは、初期値を指定しない場合の挙動を示しています。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
        
        int sum = numbers.Aggregate((total, next) => total + next);
        
        Console.WriteLine($"合計: {sum}");
    }
}
合計: 15

この場合、最初の要素1が初期値となり、次の要素2から累積処理が始まります。

初期値を指定する場合の例

初期値を指定することで、計算の開始点を変更できます。

以下のコードでは、初期値として10を指定し、合計を求めています。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
        
        int sum = numbers.Aggregate(10, (total, next) => total + next);
        
        Console.WriteLine($"合計: {sum}");
    }
}
合計: 25

この例では、初期値10が加算されるため、最終的な合計は25になります。

複雑な計算を行う場合の応用例

Aggregate()メソッドは、より複雑な計算にも対応できます。

例えば、リスト内の数値を2倍にしてから合計を求める場合、以下のように記述できます。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
        
        int sum = numbers.Aggregate(0, (total, next) => total + next * 2);
        
        Console.WriteLine($"合計(2倍した値): {sum}");
    }
}
合計(2倍した値): 30

この例では、各要素を2倍にしてから合計を求めています。

Aggregate()メソッドを使うことで、柔軟に計算処理を行うことができます。

文字列の連結

文字列連結の基本例

Aggregate()メソッドを使用して、文字列を連結する基本的な例を示します。

以下のコードでは、文字列のリストを連結しています。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        List<string> words = new List<string> { "こんにちは", "世界", "!" };
        
        string result = words.Aggregate((current, next) => current + next);
        
        Console.WriteLine($"連結結果: {result}");
    }
}
連結結果: こんにちは世界!

この例では、リスト内の全ての文字列を累積的に連結し、最終的な結果を得ています。

区切り文字を使った連結方法

区切り文字を使って文字列を連結する場合、Aggregate()メソッドを使用しつつ、区切り文字を挿入することができます。

以下のコードでは、カンマを区切り文字として使用しています。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        List<string> words = new List<string> { "りんご", "ばなな", "みかん" };
        
        string result = words.Aggregate((current, next) => current + ", " + next);
        
        Console.WriteLine($"連結結果: {result}");
    }
}
連結結果: りんご, ばなな, みかん

この例では、各文字列の間にカンマとスペースを挿入して連結しています。

空文字を初期値にする理由

文字列の連結において、初期値を空文字に設定することは重要です。

これにより、最初の要素がそのまま結果に反映され、連結処理が正しく行われます。

以下のコードでは、初期値を空文字に設定しています。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        List<string> words = new List<string> { "C#", "LINQ", "は", "楽しい" };
        
        string result = words.Aggregate("", (current, next) => current + next + " ");
        
        Console.WriteLine($"連結結果: {result.Trim()}");
    }
}
連結結果: C# LINQ は 楽しい

この例では、初期値を空文字にすることで、最初の要素が正しく連結され、余分な文字が挿入されることを防いでいます。

文字列の加工を含む連結の応用例

Aggregate()メソッドを使用して、文字列を連結する際に加工を加えることも可能です。

例えば、各単語を大文字に変換してから連結する場合、以下のように記述できます。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        List<string> words = new List<string> { "apple", "banana", "cherry" };
        
        string result = words.Aggregate("", (current, next) => current + next.ToUpper() + " ");
        
        Console.WriteLine($"連結結果: {result.Trim()}");
    }
}
連結結果: APPLE BANANA CHERRY

この例では、各単語を大文字に変換してから連結しています。

Aggregate()メソッドを使うことで、文字列の加工と連結を同時に行うことができます。

最大値の検索

最大値を求める基本例

Aggregate()メソッドを使用して、コレクション内の最大値を求める基本的な例を示します。

以下のコードでは、整数のリストから最大値を取得しています。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 3, 5, 7, 2, 8 };
        
        int max = numbers.Aggregate((currentMax, next) => currentMax > next ? currentMax : next);
        
        Console.WriteLine($"最大値: {max}");
    }
}
最大値: 8

この例では、リスト内の全ての整数を比較し、最大値を求めています。

初期値を指定する場合の注意点

Aggregate()メソッドで初期値を指定する場合、注意が必要です。

初期値がコレクション内の要素よりも大きい場合、正しい最大値が得られない可能性があります。

以下のコードでは、初期値を指定して最大値を求めています。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 3, 5, 7, 2, 8 };
        
        int max = numbers.Aggregate(10, (currentMax, next) => currentMax > next ? currentMax : next);
        
        Console.WriteLine($"最大値: {max}");
    }
}
最大値: 10

この例では、初期値10がコレクション内の要素よりも大きいため、最大値として10が返されています。

初期値を指定する際は、コレクション内の要素との関係を考慮する必要があります。

カスタムオブジェクトのプロパティを使った最大値検索

Aggregate()メソッドは、カスタムオブジェクトのプロパティを使って最大値を検索することもできます。

以下のコードでは、Personクラスのリストから年齢の最大値を求めています。

using System;
using System.Collections.Generic;
using System.Linq;
class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}
class Program
{
    static void Main()
    {
        List<Person> people = new List<Person>
        {
            new Person { Name = "Alice", Age = 30 },
            new Person { Name = "Bob", Age = 25 },
            new Person { Name = "Charlie", Age = 35 }
        };
        
        int maxAge = people.Aggregate(0, (currentMax, next) => currentMax > next.Age ? currentMax : next.Age);
        
        Console.WriteLine($"最大年齢: {maxAge}");
    }
}
最大年齢: 35

この例では、Personオブジェクトのリストから年齢の最大値を求めています。

Aggregate()メソッドを使うことで、カスタムオブジェクトのプロパティに基づいた集計が可能です。

複数条件での最大値検索の応用例

複数の条件を考慮して最大値を検索する場合、Aggregate()メソッドを組み合わせて使用することができます。

以下のコードでは、年齢が最も高い人の名前を取得しています。

using System;
using System.Collections.Generic;
using System.Linq;
class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}
class Program
{
    static void Main()
    {
        List<Person> people = new List<Person>
        {
            new Person { Name = "Alice", Age = 30 },
            new Person { Name = "Bob", Age = 25 },
            new Person { Name = "Charlie", Age = 35 }
        };
        
        string oldestPerson = people.Aggregate((currentOldest, next) => currentOldest.Age > next.Age ? currentOldest : next).Name;
        
        Console.WriteLine($"最も年齢が高い人: {oldestPerson}");
    }
}
最も年齢が高い人: Charlie

この例では、Aggregate()メソッドを使用して、年齢が最も高い人の名前を取得しています。

複数の条件を考慮した集計処理が可能であり、柔軟なデータ操作が実現できます。

Aggregate()の応用例

複数のコレクションを同時に処理する

Aggregate()メソッドを使用して、複数のコレクションを同時に処理することができます。

以下のコードでは、2つの整数リストの合計を求めています。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        List<int> numbers1 = new List<int> { 1, 2, 3 };
        List<int> numbers2 = new List<int> { 4, 5, 6 };
        
        int totalSum = numbers1.Concat(numbers2).Aggregate(0, (total, next) => total + next);
        
        Console.WriteLine($"合計: {totalSum}");
    }
}
合計: 21

この例では、Concat()メソッドを使用して2つのリストを結合し、Aggregate()メソッドで合計を求めています。

複数のコレクションを同時に処理することで、柔軟なデータ操作が可能です。

条件付きでの累積処理

条件付きで累積処理を行う場合、Aggregate()メソッドを使用して特定の条件を満たす要素のみを処理することができます。

以下のコードでは、偶数の合計を求めています。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
        
        int evenSum = numbers.Where(n => n % 2 == 0).Aggregate(0, (total, next) => total + next);
        
        Console.WriteLine($"偶数の合計: {evenSum}");
    }
}
偶数の合計: 12

この例では、Where()メソッドを使用して偶数のみをフィルタリングし、その後Aggregate()メソッドで合計を求めています。

条件付きの累積処理が簡単に実現できます。

カスタムオブジェクトのプロパティを使った集計

カスタムオブジェクトのプロパティを使用して集計を行うことも可能です。

以下のコードでは、Productクラスのリストから価格の合計を求めています。

using System;
using System.Collections.Generic;
using System.Linq;
class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}
class Program
{
    static void Main()
    {
        List<Product> products = new List<Product>
        {
            new Product { Name = "商品A", Price = 1000 },
            new Product { Name = "商品B", Price = 1500 },
            new Product { Name = "商品C", Price = 2000 }
        };
        
        decimal totalPrice = products.Aggregate(0m, (total, next) => total + next.Price);
        
        Console.WriteLine($"合計価格: {totalPrice}円");
    }
}
合計価格: 4500円

この例では、Productオブジェクトのリストから価格の合計を求めています。

カスタムオブジェクトのプロパティを使った集計が簡単に行えます。

複雑なデータ構造の集計処理

複雑なデータ構造に対してもAggregate()メソッドを使用して集計処理を行うことができます。

以下のコードでは、ネストされたリストから特定の条件を満たす要素の合計を求めています。

using System;
using System.Collections.Generic;
using System.Linq;
class Category
{
    public string Name { get; set; }
    public List<Product> Products { get; set; }
}
class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}
class Program
{
    static void Main()
    {
        List<Category> categories = new List<Category>
        {
            new Category
            {
                Name = "食品",
                Products = new List<Product>
                {
                    new Product { Name = "りんご", Price = 300 },
                    new Product { Name = "バナナ", Price = 200 }
                }
            },
            new Category
            {
                Name = "飲料",
                Products = new List<Product>
                {
                    new Product { Name = "水", Price = 100 },
                    new Product { Name = "ジュース", Price = 400 }
                }
            }
        };
        
        decimal totalPrice = categories.Aggregate(0m, (total, category) => 
            total + category.Products.Aggregate(0m, (subtotal, product) => subtotal + product.Price));
        
        Console.WriteLine($"合計価格: {totalPrice}円");
    }
}
合計価格: 1000円

この例では、ネストされたCategoryオブジェクトのリストから、全てのProductの価格を合計しています。

複雑なデータ構造に対してもAggregate()メソッドを使用することで、柔軟な集計処理が可能です。

Aggregate()と他のLINQメソッドの組み合わせ

Where()と組み合わせた条件付き集計

Where()メソッドを使用して条件を指定し、その後Aggregate()メソッドで集計を行うことができます。

以下のコードでは、偶数の合計を求めています。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
        
        int evenSum = numbers.Where(n => n % 2 == 0).Aggregate(0, (total, next) => total + next);
        
        Console.WriteLine($"偶数の合計: {evenSum}");
    }
}
偶数の合計: 12

この例では、Where()メソッドで偶数をフィルタリングし、その後Aggregate()メソッドで合計を求めています。

条件付きの集計が簡単に実現できます。

Select()と組み合わせたデータ変換

Select()メソッドを使用してデータを変換し、その後Aggregate()メソッドで集計を行うことも可能です。

以下のコードでは、文字列のリストから各文字列の長さの合計を求めています。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        List<string> words = new List<string> { "apple", "banana", "cherry" };
        
        int totalLength = words.Select(word => word.Length).Aggregate(0, (total, next) => total + next);
        
        Console.WriteLine($"文字列の長さの合計: {totalLength}");
    }
}
文字列の長さの合計: 17

この例では、Select()メソッドで各文字列の長さを取得し、その後Aggregate()メソッドで合計を求めています。

データ変換と集計を組み合わせることで、柔軟な処理が可能です。

OrderBy()と組み合わせたソート後の集計

OrderBy()メソッドを使用してデータをソートし、その後Aggregate()メソッドで集計を行うこともできます。

以下のコードでは、整数のリストをソートした後、合計を求めています。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 5, 3, 1, 4, 2 };
        
        int totalSum = numbers.OrderBy(n => n).Aggregate(0, (total, next) => total + next);
        
        Console.WriteLine($"合計: {totalSum}");
    }
}
合計: 15

この例では、OrderBy()メソッドでリストを昇順にソートし、その後Aggregate()メソッドで合計を求めています。

ソート後の集計が簡単に実現できます。

GroupBy()と組み合わせたグループごとの集計

GroupBy()メソッドを使用してデータをグループ化し、その後Aggregate()メソッドで各グループの集計を行うことができます。

以下のコードでは、Productクラスのリストからカテゴリごとの価格の合計を求めています。

using System;
using System.Collections.Generic;
using System.Linq;
class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Category { get; set; }
}
class Program
{
    static void Main()
    {
        List<Product> products = new List<Product>
        {
            new Product { Name = "りんご", Price = 300, Category = "食品" },
            new Product { Name = "バナナ", Price = 200, Category = "食品" },
            new Product { Name = "水", Price = 100, Category = "飲料" },
            new Product { Name = "ジュース", Price = 400, Category = "飲料" }
        };
        
        var categorySums = products.GroupBy(p => p.Category)
            .Select(g => new
            {
                Category = g.Key,
                TotalPrice = g.Aggregate(0m, (total, next) => total + next.Price)
            });
        
        foreach (var category in categorySums)
        {
            Console.WriteLine($"{category.Category}の合計価格: {category.TotalPrice}円");
        }
    }
}
食品の合計価格: 500円
飲料の合計価格: 500円

この例では、GroupBy()メソッドでカテゴリごとにグループ化し、各グループの価格の合計を求めています。

グループごとの集計が簡単に実現できます。

まとめ

この記事では、C#のAggregate()メソッドの基本的な使い方から応用例までを振り返りました。

特に、数値の合計や文字列の連結、最大値の検索といった具体的な処理方法を通じて、Aggregate()メソッドの柔軟性と強力さを強調しました。

これを機に、実際のプロジェクトやデータ処理の場面でAggregate()メソッドを活用し、より効率的なコーディングを目指してみてはいかがでしょうか。

関連記事

Back to top button