2016-06-01 3 views
3

私はすべてのコレクションにSpring4Dを使用しています。IsFirstとIsLast関数を持つ列挙子を実装する方法は?

現在、列挙子の現在の値がコレクションの最初のもの(簡単かどうか)または最後のもの(ハードなもの)かどうかを知る必要がある状況があります。

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の機能はどのように実装できますか?

+0

要素が最初か最後か、まったく違うことができない場合は、その知識で何を達成しようとしているのですか? –

+0

私たちは、[control break](https://en.wikipedia.org/wiki/Control_break)というやや珍しい形で使っています。 –

+0

私が言ったように、これを行う別の方法があるかもしれません - たとえば、ウィキペディアの記事では、TEnumerable.GroupByを使ってグループ化することができます。 –

答えて

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; 

は、これは基本的なアルゴリズムですが、IsFirst/IsLastを提供するために、IEnumerator<T>ためデコレータにそれを置くことができます - あなただけの現在の要素をバッファリングして調べる必要があり1つは、現在のものが最後であるかどうかを見るために先に進む。

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; 
関連する問題