如何实现具有IsFirst和IsLast函数的枚举器?

Jen*_*off 3 delphi enumerator spring4d delphi-xe7

我正在使用Spring4D进行所有收藏.

现在有一种情况我必须知道枚举器的当前值是集合中的第一个(很容易)还是最后一个(很难).

program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils,
  Spring.Collections;

var
  Enumerable: IEnumerable<Integer>;
  Enumerator: IEnumerator<Integer>;

begin
  Enumerable := TEnumerable.Query<Integer>(TArray<Integer>.Create(1, 2, 3, 4, 5)
    ) as IEnumerable<Integer>;
  Enumerator := Enumerable.GetEnumerator;
  while Enumerator.MoveNext do
  begin
    WriteLn('Value = ', Enumerator.Current);
    WriteLn('First in collection? ', Enumerator.CurrentIsFirst);
    WriteLn('Last in collection? ', Enumerator.CurrentIsLast);
  end;
  ReadLn;

end.
Run Code Online (Sandbox Code Playgroud)

CurrentIsFirst 可以使用本地布尔值实现,该布尔值在第一个值通过后重置.

但是,我不知道一种简单的实施方法CurrentIsLast.

它应该能够处理延迟集合,因为它们可能包含太多值以适应内存.

我该如何实现这样的CurrentIsLast功能?

Ste*_*nke 6

只需在迭代期间使用一个标志:

if Enumerator.MoveNext then
begin
  flag := True;
  repeat
    WriteLn('Value = ', Enumerator.Current);
    WriteLn('First in collection? ', flag);
    flag := not Enumerator.MoveNext;
    WriteLn('Last in collection? ', flag);
  until flag;
end;
Run Code Online (Sandbox Code Playgroud)

这是基本的算法,但你可以把它放到装饰器中IEnumerator<T>来提供IsFirst/ IsLast- 你只需要缓冲当前元素并提前查看当前元素是否是最后一个.

type
  IEnumeratorEx<T> = interface(IEnumerator<T>)
    function IsFirst: Boolean;
    function IsLast: Boolean;
  end;

  TEnumeratorState = (Initial, First, Only, Running, Last, Finished);
  TEnumeratorEx<T> = class(TEnumeratorBase<T>, IEnumeratorEx<T>)
  private
    fSource: IEnumerator<T>;
    fCurrent: T;
    fState: TEnumeratorState;
    function IsFirst: Boolean;
    function IsLast: Boolean;
  protected
    function GetCurrent: T; override;
    function MoveNext: Boolean; override;
  public
    constructor Create(const source: IEnumerator<T>);
  end;

constructor TEnumeratorEx<T>.Create(const source: IEnumerator<T>);
begin
  inherited Create;
  fSource := source;
end;

function TEnumeratorEx<T>.GetCurrent: T;
begin
  Result := fCurrent;
end;

function TEnumeratorEx<T>.IsFirst: Boolean;
begin
  Result := fState in [First, Only];
end;

function TEnumeratorEx<T>.IsLast: Boolean;
begin
  Result := fState in [Only, Last];
end;

function TEnumeratorEx<T>.MoveNext: Boolean;
begin
  case fState of
    Initial:
      if fSource.MoveNext then
        fState := First
      else
        fState := Finished;
    First:
      fState := Running;
    Only, Last:
      fState := Finished;
  end;

  Result := fState <> Finished;
  if Result then
  begin
    fCurrent := fSource.Current;
    if not fSource.MoveNext then
      Inc(fState);
  end;
end;
Run Code Online (Sandbox Code Playgroud)