Delphiのfor-inループをサポートするクラスでFizz-Buzz問題を解く

Delphiは、for-in スタイルの反復をサポートしています。

自作のクラスが for-in ループをサポートするには次の条件を満たす必要があります。

  • クラスまたはインターフェイスは、GetEnumerator() というパブリック インスタンス メソッドを含んでいる必要があります。 GetEnumerator() メソッドは、クラス、インターフェイス、またはレコード型を返す必要があります。
  • GetEnumerator() が返すクラス、インターフェイス、レコードには、MoveNext() というパブリック インスタンス メソッドが含まれている必要があります。 MoveNext() メソッドは、Boolean を返す必要があります。
  • GetEnumerator() が返すクラス、インターフェイス、レコードには Current というパブリック インスタンス読み取り専用プロパティが含まれている必要があります。 Current プロパティの型は、コレクションに含まれる型である必要があります。

宣言と文(Delphi) – RAD Studio XE3」より

試しに、Fizz-Buzz問題を解くクラスを作成してみました。

1から100までの数をプリントするプログラムを書け。ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、3と5両方の倍数の場合には「FizzBuzz」とプリントすること。

Fizz-Buzz問題」より

TFizzBuzzクラスはfor-inループをサポートし、Fizz-Buzz問題の解答を返します。

var
  FizzBuzz: TFizzBuzz;
  S: string;
begin
  FizzBuzz := TFizzBuzz.Create;
  for s in FizzBuzz do
    Writeln(s);

実行結果

1
2
Fizz
4
Buzz
Fizz
7
…

for-inループをサポートするためTFizzBuzzクラスはGetEnumeratorメソッドを持ちます。
GetEnumeratorメソッドはTFizzBuzzEnumeratorオブジェクトを返します。

type
  TFizzBuzz = class
  public
    function GetEnumerator: TFizzBuzzEnumerator;
  end;

function TFizzBuzz.GetEnumerator: TFizzBuzzEnumerator;
begin
  Result := TFizzBuzzEnumerator.Create;
end;

TFizzBuzzEnumeratorクラスは、for-inループをサポートするためMoveNext()メソッドとCurrentプロパティを持ちます。

type
  TFizzBuzzEnumerator = class
  private
    FIndex: Integer;
    function GetCurrent: string;
  public
    function MoveNext: Boolean;
    property Current: string read GetCurrent;
  end;

MoveNext()メソッドはループの回数が100回に達したかを判定します。

function TFizzBuzzEnumerator.MoveNext: Boolean;
begin
  Result := FIndex < 100;
  if Result then
    Inc(FIndex);
end;

GetCurrentメソッドは、ループの回数が3の倍数のときは「Fizz」、5の倍数のときは「Buzz」、3と5両方の倍数の場合には「FizzBuzz」、それ以外の時はループの回数を返します。

function TFizzBuzzEnumerator.GetCurrent: string;
begin
  if FIndex mod 15 = 0 then
    Result := 'FizzBuzz'
  else if FIndex mod 3 = 0 then
    Result := 'Fizz'
  else if FIndex mod 5 = 0 then
    Result := 'Buzz'
  else
    Result := IntToStr(FIndex);
end;

以上で完成しました。

classではなくrecordを使った方がFreeの必要がなくなるので、よりよかったかもしれません。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください