はじめに
これは FizzBuzz Advent Calendar 2017 とも Delphi Advent Calendar 2017 とも全く関係のない記事です (w
Delphi って begin~end があるのでコードを極端に短く書くのは苦手です。コードゴルフとかはその辺りを考慮しないので特定の言語が常に上位に来る傾向があります。FizzBuzz も例にもれず、Delphi で普通に書いたら長くなります...読みやすいですけどね。
それと、とあるメソッドや文法が標準で実装されているかで短く書けますよね。例えば最小公倍数 (LCM) や三項演算子が実装されていると短く書けます。
それだったら...
コード
FizzBuzz を返すコレクションを考えてみます。コードはこんな感じで書けるといいですね。
procedure TForm1.Button1Click(Sender: TObject);
var
s: string;
begin
Memo1.Clear;
for s in FizzBuzz(100) do
Memo1.Lines.Append(s);
end;
FizzBuzz がリストアップされるコレクションを使えばコードが短くて済みます。フォームはこんな感じでボタンとメモだけが貼ってあります。
実装はこうなりました。Delphi 2005 以降で動作すると思います。恐らく FPC でも動作するでしょう。
unit uFizzBuzzCollection;
{$IFDEF FPC}
{$modeswitch ADVANCEDRECORDS}
{$ENDIF}
interface
uses
SysUtils, Types;
type
TFizzBuzzEnumerator = class;
TFizzBuzz = record
private
Ffrom: Integer;
Fthrough: Integer;
public
constructor Create(from: Integer; through: Integer);
function GetEnumerator: TFizzBuzzEnumerator;
end;
TFizzBuzzEnumerator = class
Container: TFizzBuzz;
Index: Integer;
public
constructor Create(AContainer : TFizzBuzz);
function GetCurrent: string;
function MoveNext: Boolean;
property Current: string read GetCurrent;
end;
function FizzBuzz(from: Integer; through: Integer): TFizzBuzz; overload
function FizzBuzz(Count: Integer): TFizzBuzz; overload;
implementation
function FizzBuzz(from, through: Integer): TFizzBuzz;
begin
Result := TFizzBuzz.Create(from, through);
end;
function FizzBuzz(Count: Integer): TFizzBuzz;
begin
Result := TFizzBuzz.Create(1, Count);
end;
{ TFizzBuzz }
constructor TFizzBuzz.Create(from, through: Integer);
begin
Ffrom := from;
Fthrough := through;
end;
function TFizzBuzz.GetEnumerator: TFizzBuzzEnumerator;
begin
Result := TFizzBuzzEnumerator.Create(Self);
end;
{ TFizzBuzzEnumerator }
constructor TFizzBuzzEnumerator.Create(AContainer: TFizzBuzz);
begin
inherited Create;
Container := AContainer;
Index := -1;
end;
function TFizzBuzzEnumerator.GetCurrent: string;
var
v: Integer;
begin
v := Container.Ffrom + Index;
if ((v mod 3) + (v mod 5)) = 0 then
Result := 'Fizz Buzz'
else if (v mod 3) = 0 then
Result := 'Fizz'
else if (v mod 5) = 0 then
Result := 'Buzz'
else
Result := IntToStr(v);
end;
function TFizzBuzzEnumerator.MoveNext: Boolean;
begin
result := False;
if ((Container.Ffrom + Index + 1) > Container.Fthrough) then
Exit;
result := True;
Inc(Index);
end;
end.
ちゃんと動作しますね!
おわりに
これで Delphi でも FizzBuzz を短く書けるようになりました...まぁ、Delphi はその場で変数の宣言ができないので、他の言語でFizzBuzz コレクションを実装されたらあまり意味はないんですけどね (w
追記:
Delphi 10.3 Rio にて変数のインライン宣言が可能になりました!
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Clear;
for var s in FizzBuzz(100) do
Memo1.Lines.Append(s);
end;
型推論もあるので多少は短く書けるようになりました!
See Also: