yield returnによるイテレーターメソッド
一度に1要素ずつシーケンスを生成します。
「yield returnによるイテレーターメソッド」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。
イテレーターメソッドとは
イテレーターメソッドは、yield return を使って値を一度に 1 つずつ生成するメソッドです。コンパイラーがこれをステートマシンに変換するため、自分でリストを構築して管理する必要はありません。
最初の yield return
各 yield return は 1 つの値を呼び出し側に返し、メソッドを一時停止します。次の反復では、その文の直後から実行が再開されます。
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<int> FirstThree()
{
yield return 1;
yield return 2;
yield return 3;
}
public static void Main()
{
foreach (var n in FirstThree())
Console.WriteLine(n);
}
}ループ内の yield return
ほとんどのイテレーターは、ループ内で値を生成します。ここでは、コレクションを一度も割り当てずに、最初の count 個の偶数を生成します。
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<int> Evens(int count)
{
for (int i = 0; i < count; i++)
yield return i * 2;
}
public static void Main()
{
foreach (var n in Evens(5))
Console.WriteLine(n);
}
}メソッドは IEnumerable を返す
イテレーターメソッドは、IEnumerable<T> または IEnumerator<T>(あるいは非ジェネリック版)を返す必要があります。値を伴う return は記述せず、yield return だけを使用します。
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<string> Greetings()
{
yield return "hello";
yield return "hi";
yield return "hey";
}
public static void Main()
{
foreach (var g in Greetings())
Console.WriteLine(g);
}
}実行は一時停止と再開を繰り返す
yield の間の状態は自動的に保持されます。ローカル変数は一時停止している間も値を保持するため、累計値を生成する処理を簡単に記述できます。
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<int> RunningTotal(IEnumerable<int> nums)
{
int total = 0;
foreach (var n in nums)
{
total += n;
yield return total;
}
}
public static void Main()
{
foreach (var t in RunningTotal(new[] { 1, 2, 3, 4 }))
Console.WriteLine(t);
}
}無限シーケンスを生成する
値は必要になったときに生成されるため、イテレーターでは無限シーケンスも安全に表現できます。値の取得をいつ停止するかは呼び出し側が決めます。
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<int> Naturals()
{
int i = 1;
while (true) yield return i++;
}
public static void Main()
{
int taken = 0;
foreach (var n in Naturals())
{
Console.WriteLine(n);
if (++taken == 5) break;
}
}
}入力シーケンスを変換する
イテレーターはパイプラインの構築に適しています。1 つのシーケンスから項目を読み取り、変換して、結果を遅延的に生成できます。
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<string> Labelled(IEnumerable<int> nums)
{
foreach (var n in nums)
yield return "item-" + n;
}
public static void Main()
{
foreach (var s in Labelled(new[] { 10, 20, 30 }))
Console.WriteLine(s);
}
}イテレーターでフィルター処理する
フィルター処理では、必要な項目だけを生成します。スキップされた項目は生成されないため、後続のコードからは見えません。
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<int> OnlyPositive(IEnumerable<int> nums)
{
foreach (var n in nums)
if (n > 0) yield return n;
}
public static void Main()
{
foreach (var n in OnlyPositive(new[] { -2, 5, -1, 8 }))
Console.WriteLine(n);
}
}コンパイラーがステートマシンを構築する
内部では、コンパイラーがイテレーターを IEnumerator<T> を実装するクラスに書き換え、非公開の状態フィールドと Current の値を追跡します。この仕組みはすべて自動的に用意されます。
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<char> Letters()
{
yield return 'a';
yield return 'b';
yield return 'c';
}
public static void Main()
{
IEnumerator<char> e = Letters().GetEnumerator();
while (e.MoveNext())
Console.WriteLine(e.Current);
}
}複数のイテレーターを組み合わせる
各イテレーターが IEnumerable<T> を返すため、イテレーターは自然につなげられます。1 つのイテレーターの出力を次のイテレーターに渡して、読みやすいパイプラインを構築できます。
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<int> Range(int start, int count)
{
for (int i = 0; i < count; i++) yield return start + i;
}
static IEnumerable<int> Squares(IEnumerable<int> nums)
{
foreach (var n in nums) yield return n * n;
}
public static void Main()
{
foreach (var n in Squares(Range(1, 4)))
Console.WriteLine(n);
}
}自分で試す
入力シーケンスを固定サイズのチャンクに分割するイテレーターを書いてみましょう。必要に応じてリストを生成することで、1 つの簡潔なイテレーターにどれだけのロジックを収められるかを確認できます。
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<List<int>> Batch(IEnumerable<int> source, int size)
{
var bucket = new List<int>();
foreach (var n in source)
{
bucket.Add(n);
if (bucket.Count == size) { yield return bucket; bucket = new List<int>(); }
}
if (bucket.Count > 0) yield return bucket;
}
public static void Main()
{
foreach (var group in Batch(new[] { 1, 2, 3, 4, 5 }, 2))
Console.WriteLine(string.Join(",", group));
}
}クイックチェック
イテレーターメソッドの動作を思い出してみましょう。
まとめ
イテレーターメソッドは yield return を使って、必要に応じてシーケンスを生成します。
- メソッドは
IEnumerable<T>またはIEnumerator<T>を返します。 - 各
yield returnは 1 つの値を生成して一時停止し、ローカル状態を保持します。 - 無限シーケンスも安全に表現できます。
- ステートマシンはコンパイラーが生成します。
よくある質問
「yield returnによるイテレーターメソッド」レッスンは無料ですか?
はい。「yield returnによるイテレーターメソッド」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。
「yield returnによるイテレーターメソッド」で何を学びますか?
一度に1要素ずつシーケンスを生成します。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C# Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「yield returnによるイテレーターメソッド」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC# Academyレッスンでコードを書いて実行できますか?
はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- yield returnによるイテレーターメソッド
- yield breakと早期終了
- 遅延評価のセマンティクス
- カスタム列挙可能型