delphi-collを使ってみる(5)

先日参加した「わんくま同盟大阪勉強会#58」の「LINQ再入門」の例題がわかりやすかったので、Delphiで同じことをしてみました。

お題

  • Project Euler Problem2
    • フィボナッチ数列の項は前の2つの項の和である. 最初の2項を1, 2 とすれば, 最初の10項は以下の通りである.
    • 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …
    • 数列の項の値が400万以下の, 偶数値の項の総和を求めよ.

回答サンプル

function Problem1(Limit: Integer): Integer;
var
  Sum, A, B, Temp: Integer;
begin
  //合計処理
  Sum := 0;
  //数列の生成処理
  A := 1;
  B := 0;

  while B < Limit do //終了条件
  begin
    //数列の生成処理
    Temp := A;
    A := B;
    B := A + Temp;

    if B mod 2 = 0 then //抽出条件
    begin
      Inc(Sum, B); //合計処理
    end;
  end;
  Result := Sum; //合計処理
end;

このコードは、「数列の生成処理」「終了条件」「抽出条件」「合計処理」が入り交じっています。

リファクタリング

delphi-collを使ってリファクタリングしてみます。

uses
  Collections.Base,
  Collections.Lists;

function Problem2(Limit: Integer): Integer;
var
  FibonacchiNumber: ISequence<Integer>;
begin
  //数列の生成処理
  FibonacchiNumber:= TFibonacchiNumber.Create;
  Result := FibonacchiNumber.TakeWhile( //終了条件
    function(Arg: Integer): Boolean
    begin
      Exit(Arg < Limit);
    end).Where( //抽出条件
    function(Arg: Integer): Boolean
    begin
      Exit(Arg mod 2 = 0);
    end).Aggregate( //合計処理
    function(Arg1, Arg2: Integer): Integer
    begin
      Exit(Arg1 + Arg2);
    end);
end;

同じ処理がまとまったので、ソースコードが読みやすくなりました。

数列の生成処理

フィボナッチ数列の値を生成するTFibonacchiNumberは次のようになります。

uses
  Collections.Base,
  Collections.Lists;

type
  TFibonacchiNumber = class(Collections.Base.TSequence<Integer>)
  private type
    TFibonacchiNumberEnumerator = class(TInterfacedObject,
      Collections.Base.IEnumerator<Integer>)
    private
      A: Integer;
      B: Integer;
    public
      constructor Create;
      function GetCurrent: Integer;
      function MoveNext: Boolean;
      property Current: Integer read GetCurrent;
    end;
  public
    function GetEnumerator: Collections.Base.IEnumerator<Integer>; override;
  end;

{ TFibonacchiNumber }

function TFibonacchiNumber.GetEnumerator: Collections.Base.IEnumerator<Integer>;
begin
  Result := TFibonacchiNumberEnumerator.Create;
end;

{ TFibonacchiNumber.TFibonacchiNumberEnumerator }

constructor TFibonacchiNumber.TFibonacchiNumberEnumerator.Create;
begin
  A := 1;
  B := 0;
end;

function TFibonacchiNumber.TFibonacchiNumberEnumerator.GetCurrent: Integer;
begin
  Result := B;
end;

function TFibonacchiNumber.TFibonacchiNumberEnumerator.MoveNext: Boolean;
var
  Temp: Integer;
begin
  Result := True;

  Temp := A;
  A := B;
  B := A + Temp;
end;

コメントを残す

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

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