C#

C# | イテレータとは何か? 使うメリット紹介

2024年5月10日

本ページはプロモーションが含まれています

C#イテレータアイキャッチ画像

イテレータ(Iterator)は、コレクションやシーケンスの要素を順番に取り出すための仕組みです。

具体的には、foreach ループを使ってコレクションの各要素にアクセスする際に、イテレータが内部で使用されます。

イテレータは、大きなデータセットや複雑なデータ構造を効率的に処理する際に非常に便利です。

以下は、イテレータの簡単な使用例です。

using System;
using System.Collections;

public class Program
{
    public static void Main()
    {
        // イテレータの使用例
        var numbers = GetNumbers(); // イテレータを利用した数列の取得

        foreach (var number in numbers)
        {
            Console.WriteLine(number);
        }
    }

    // イテレータを定義するメソッド
    public static IEnumerable GetNumbers()
    {
        yield return 1; // 数列の要素をyield returnで返す
        yield return 2;
        yield return 3;
    }
}

実行結果

1
2
3

イテレータの主な疑問や問題点を挙げてみます。

  • イテレータの実際の使われ方は?
  • イテレータのメリットは?
  • イテレータ内で例外が発生した場合、どのように処理されるのか?

この記事ではこれらについても詳しく解説します。

イテレータとは?

ポイント

イテレータは、反復子とも呼ばれ、プログラム内の要素を順番に反復処理するための仕組みです。
イテレータを使用することで、コレクション内の要素や他のデータ構造の要素をひとつずつ処理することができます。

例えば、配列、リスト、セット、マップなどのコレクションや、文字列、ファイルの行、ジェネレータなどのデータ構造を反復処理する際にイテレータが活用されます。

イテレータは特に、大規模なデータセットや無限のシーケンスを効率的に処理する場合に役立ちます。
また、イテレータは遅延評価を行うため、必要な要素が必要になるまで要素を生成せず、メモリの効率的な利用が可能です。

イテレータの定義

イテレータは、IEnumerable<T> インターフェースを実装したメソッドとして定義されます。

public static IEnumerable<T> MyIterator()
{
    yield return "March";
}

コードの解説

  • メソッド定義
    • public static IEnumerable<T> MyIterator() というメソッドを定義しています。IEnumerable<T> を返すことを示していますが、T は具体的な型が必要です。この例では型が明記されていないため、実際には IEnumerable<string> など具体的な型である必要があります。
  • yield return
    • yield return "March"; により、"March" という文字列を返します。yield return は、メソッドの呼び出し元に値を逐次的に返すイテレーターを作成するために使われます。
  • イテレーション
    • メソッドを呼び出すと、IEnumerable<T> を介してイテレーション(繰り返し処理)が可能になります。この例では、"March" だけを返すイテレーターが作成されます。

イテレータの使用例

イテレータはループ処理と一緒に使用されることが一般的です。
以下の2つの例を紹介します。

  • イテレータとforeachを使った例
  • イテレータとwhileを使った例

1~5までの数字をforeach文でコンソールに出力するプログラム

以下のコードは、SimpleIterator メソッドが IEnumerable<int> を返し、yield return ステートメントを使用して順番に整数を返します。
Main メソッドでは、foreach ループを使って SimpleIterator メソッドから得られる値を順番に処理し、コンソールに出力します。

using System;
using System.Collections.Generic;

public class Program
{
    public static IEnumerable<int> SimpleIterator()
    {
        yield return 1;
        yield return 2;
        yield return 3;
        yield return 4;
        yield return 5;
    }
    
    public static void Main()
    {
        foreach (int num in SimpleIterator())
        {
            Console.WriteLine(num);
        }
    }
}

コードの解説

  • イテレータメソッドの定義public static IEnumerable<int> SimpleIterator()
    • IEnumerable<int> はメソッドが整数 (int) の列を返すことを示します。
  • yield return キーワードyield return 1;
    • yield return を使うことで、メソッドは 1, 2, 3, 4, 5 の値を逐次的に返します。
  • ループ処理foreach (int num in SimpleIterator())
    • SimpleIterator メソッドを呼び出し、その戻り値である IEnumerable<int> を列挙します。
    • foreach ループは、SimpleIterator から順に値を取り出して num という変数に格納します。
    • num に格納された各値をコンソールに出力します。

実行結果

1
2
3
4
5

1~5までの数字をwhile文でコンソールに出力するプログラム

以下のコードは、while ループを使用して先ほどのプログラムと同じ結果を得る例です。

using System;
using System.Collections.Generic;

public class Program
{
    public static IEnumerable<int> SimpleIterator()
    {
        yield return 1;
        yield return 2;
        yield return 3;
        yield return 4;
        yield return 5;
    }
    
    public static void Main()
    {
        IEnumerator<int> enumerator = SimpleIterator().GetEnumerator(); 
        
        while (enumerator.MoveNext()) 
        {
            Console.WriteLine(enumerator.Current);
        }
    }
}

コードの解説

  • イテレータメソッドの定義public static IEnumerable<int> SimpleIterator()
  • yield return キーワードyield return 1;
  • イテレータの取得SimpleIterator().GetEnumerator(): SimpleIterator
    • SimpleIterator().GetEnumerator(): SimpleIterator メソッドを呼び出し、その戻り値である IEnumerable<int> に対して GetEnumerator メソッドを呼び出します。これにより、IEnumerator<int> オブジェクトが返されます。
    • IEnumerator<int>: このインターフェースは、コレクション内の要素を順に取得するためのメソッドを提供します。
  • 列挙の開始while (enumerator.MoveNext())
    • while (enumerator.MoveNext()): MoveNext メソッドを呼び出すことで、シーケンス内の次の要素に移動します。次の要素が存在する場合は true を返し、存在しない場合は false を返します。
    • enumerator.Current: Current プロパティは、現在の要素を返します。MoveNext が呼び出されるまでは初期位置にあり、Current は未定義です。
    • Console.WriteLine(enumerator.Current): 現在の要素をコンソールに出力します。

MoveNext() メソッドとは
MoveNext() メソッドは、列挙子がコレクション内の次の要素に進むためのメソッドです。次の要素が存在する場合は true を返し、存在しない場合は false を返します。初期状態ではコレクションの最初の要素の前に位置しており、最初に呼び出されたときに最初の要素に進みます。

実行結果

1
2
3
4
5


上記の例ではwhileループでの使用を紹介しましたが、イテレータを使用する際は、foreach ループを使うのが一般的です。
foreach ループは、列挙可能なコレクション(IEnumerable<T> を実装したオブジェクト)を簡潔かつ直感的に列挙する方法を提供します。
これにより、イテレータの詳細な管理を必要とせずにコレクションの要素を順に処理できます。

イテレータの実際の使われ方

イテレータは通常、リソースの効率的な管理やコードの再利用性を向上させるために、独立したプロジェクトやクラスライブラリ内に作成されます。

その後、他のプロジェクトやクラスからそれを呼び出して使用します。

イテレータのメリットとは?

イテレータは、リソースを効率的に管理し、コードを簡潔かつ読みやすくし、遅延実行でパフォーマンスを向上させます。
カスタムシーケンスの実装も容易です。

イテレータは、要素のシーケンスを生成し、foreachループなどのループ構文を使用してその要素を処理します。
イテレータを使用することで、データの生成と処理を分離し、必要に応じて要素を遅延評価することができます。
これにより、大規模なデータセットを効率的に処理することができます。

簡単に言うと、メモリ使用量が多い時にはイテレータ + foreach文やwhile文などのループ処理を使い、メモリ使用量が少ない時にはイテレータを使わないループ処理、という感じで使い分けすると良いと思います。

イテレータ + ループ処理 を使用する場面

  • メモリの使用量を最適化したい場合。
  • 大規模なデータセットを効率的に処理したい場合。
  • 無限シーケンスを扱う場合。
  • 複雑なデータ構造を反復処理したい場合。
  • 遅延評価が必要な場合。
  • 特定の条件を満たす要素のみを反復処理したい場合。

ループ処理のみで使用する場面

  • メモリの使用量が少ないデータセットを処理する場合。
  • 単純な反復処理を行い、コードの可読性を重視する場合。
  • データセット全体を一度にメモリに読み込むことが可能な場合。
  • 開発速度を重視し、シンプルで直感的な反復処理を行いたい場合。

イテレータの例外処理

イテレータ内で例外が発生した場合、その例外はイテレータを呼び出した側でキャッチする必要があります。

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        try
        {
            foreach (var number in GetNumbers())
            {
                Console.WriteLine(number);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"例外が発生しました: {ex.Message}");
        }
    }

    static IEnumerable<int> GetNumbers()
    {
        yield return 1;
        yield return 2;
        yield return 3;

        // 例外を発生させる
        throw new InvalidOperationException("サンプル例外");

        yield return 4;
        yield return 5;
    }
}

コードの解説

  • イテレータメソッド (GetNumbers)
    • yield returnを使って順番に値を返します。
    • 意図的に例外 (InvalidOperationException) を発生させています。この例外はイテレータメソッド内で発生しますが、例外はイテレータの消費者側で処理されます。
  • メインメソッド (Main)
    • foreachループでGetNumbersメソッドから値を取得します。
    • foreachループ内で例外が発生すると、その例外はcatchブロックでキャッチされ、エラーメッセージが表示されます。

実行結果

1
2
3
例外が発生しました: サンプル例外

まとめ

  • イテレータ
    • イテレータは、C# において要素の逐次的な処理を可能にする概念です。
    • イテレータは、yield return ステートメントを使用して要素を逐次的に生成します。
    • yield return ステートメントは、現在のメソッドの実行を一時停止し、呼び出し元に値を返します。
  • イテレータのメリット
    • メモリの効率的な使用: イテレータは要素を必要に応じて逐次的に生成するため、大規模なデータセットや無限シーケンスを扱う際にメモリの使用量を最適化できます。
    • 遅延評価: イテレータは要素の生成を遅延させるため、必要なときにのみ要素が生成されます。これにより、無駄な計算やリソースの消費を避けることができます。

Follow me!

-C#
-,

PAGE TOP