3

我对所有集合都使用 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.

CurrentIsFirst可以使用本地布尔值来实现,一旦第一个值通过,该布尔值就会被重置。

但是我不知道实现的简单方法CurrentIsLast

它应该能够处理惰性集合,因为它们可能包含太多无法放入内存的值。

我怎样才能实现这样的CurrentIsLast功能?

4

1 回答 1

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;

这是基本算法,但您可以将其放入装饰器中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;
于 2016-06-01T14:30:23.817 回答