Delphi / Pascal IteratorWrapper

Date: 2024-10-21
uses
  System.SysUtils, System.Generics.Collections;

type
  TIteratorWrapper<T> = class
  private
    FEnumerable: TEnumerable<T>;
  public
    constructor Create(Iterable: TEnumerable<T>);
    function Map(Func: TFunc<T, T>): TIteratorWrapper<T>;
    function Filter(Func: TFunc<T, Boolean>): TIteratorWrapper<T>;
    function Take(N: Integer): TIteratorWrapper<T>;
    function ToArray: TArray<T>;
    function GetEnumerator: TEnumerator<T>;
  end;

constructor TIteratorWrapper<T>.Create(Iterable: TEnumerable<T>);
begin
  FEnumerable := Iterable;
end;

function TIteratorWrapper<T>.Map(Func: TFunc<T, T>): TIteratorWrapper<T>;
var
  Enumerator: TEnumerator<T>;
begin
  Result := TIteratorWrapper<T>.Create(
    TEnumerable<T>.Create(
      function: TEnumerator<T>
      begin
        Enumerator := FEnumerable.GetEnumerator;
        Result := TEnumerator<T>.Create(
          function: Boolean
          begin
            Result := Enumerator.MoveNext;
            if Result then
              Enumerator.Current := Func(Enumerator.Current);
          end
        );
      end
    )
  );
end;

function TIteratorWrapper<T>.Filter(Func: TFunc<T, Boolean>): TIteratorWrapper<T>;
var
  Enumerator: TEnumerator<T>;
begin
  Result := TIteratorWrapper<T>.Create(
    TEnumerable<T>.Create(
      function: TEnumerator<T>
      begin
        Enumerator := FEnumerable.GetEnumerator;
        Result := TEnumerator<T>.Create(
          function: Boolean
          begin
            while Enumerator.MoveNext do
            begin
              if Func(Enumerator.Current) then
                Exit(True);
            end;
            Result := False;
          end
        );
      end
    )
  );
end;

function TIteratorWrapper<T>.Take(N: Integer): TIteratorWrapper<T>;
var
  Count: Integer;
  Enumerator: TEnumerator<T>;
begin
  Count := 0;
  Result := TIteratorWrapper<T>.Create(
    TEnumerable<T>.Create(
      function: TEnumerator<T>
      begin
        Enumerator := FEnumerable.GetEnumerator;
        Result := TEnumerator<T>.Create(
          function: Boolean
          begin
            if Count < N then
            begin
              Result := Enumerator.MoveNext;
              Inc(Count);
            end
            else
              Result := False;
          end
        );
      end
    )
  );
end;

function TIteratorWrapper<T>.ToArray: TArray<T>;
var
  Enumerator: TEnumerator<T>;
  List: TList<T>;
begin
  List := TList<T>.Create;
  try
    Enumerator := FEnumerable.GetEnumerator;
    while Enumerator.MoveNext do
      List.Add(Enumerator.Current);
    Result := List.ToArray;
  finally
    List.Free;
  end;
end;

function TIteratorWrapper<T>.GetEnumerator: TEnumerator<T>;
begin
  Result := FEnumerable.GetEnumerator;
end;

{ Helper functie }
function From<T>(Iterable: TEnumerable<T>): TIteratorWrapper<T>;
begin
  Result := TIteratorWrapper<T>.Create(Iterable);
end;

procedure TestLazyIterator;
var
  Numbers: TArray<Integer>;
  Result: TArray<Integer>;
begin
  Numbers := TArray<Integer>.Create(1, 2, 3, 4, 5);

  Result := From<Integer>(TArray<Integer>.Create(Numbers))
    .Map(
      function(X: Integer): Integer
      begin
        Result := X * 2;
      end)
    .Filter(
      function(X: Integer): Boolean
      begin
        Result := X > 5;
      end)
    .Take(2)
    .ToArray;

  WriteLn('Resultaat: ', String.Join(', ', Result));  // Resultaat: 6, 8
end;

begin
  TestLazyIterator;
end.
89750cookie-checkDelphi / Pascal IteratorWrapper