2012-02-05 12 views
5

は、私は非常に私はC++イテレータのようなC#でイテレータを使用するにはどうすればよいC#のポインタ、イテレータとジェネリック

を困惑のですか?私はBegin()またはEnd()アクセサを見つけることができません、イテレータを宣言する方法を見つけることさえできません。私はIenumeratorについて読んだ。私の目標は、マージ機能を実装することです。以下は、C++で書かれたMerge関数の一部です。ほとんどの場合、整数ではなく参照型を使用することを除いて、表示されているものと同等のC#を探しています。

void merge(vector<int>::iterator left, vector<int>::iterator right, vector<int>::iterator  leftEnd, vector<int>::iterator rightEnd, vector<int>::iterator full) 
{ 

    while(left != leftEnd && right!= rightEnd) //compare left and right until the end of the vector is reached 
    { 
     if(*right < *left)  //right < left so insert right to the output vector and advance the iterators 
     { 
      *full++ = *right++; 
     } 
     else     //left < right so insert left to the output vector and advance the iterators 
     { 
      *full++ = *left++; 
     } 
    } 

    while(left != leftEnd) //copy any remaining elements into the output from left 
    { 
     *full++ = *left++; 
    } 
} 

また、どのコレクションを使用する必要がありますか? (現在、私はList<T>LinkedList<T>を試しています)。 - .NETイテレータを使用すると、基になるコレクションに変更を加えることはできません

ここ
bool leftValid = left.MoveNext(); 
bool rightValid = right.MoveNext(); 

while (leftValid && rightValid) 
{ 
    if (right.Current < left.Current) 
    { 
     full.Add(right.Current); 
     rightValid = right.MoveNext(); 
    } 
    else 
    { 
     full.Add(left.Current); 
     leftValid = left.MoveNext(); 
    } 
} 

while (leftValid) 
{ 
    full.Add(left.Current); 
    leftValid = left.MoveNext();  
} 

while (rightValid) 
{ 
    full.Add(right.Current); 
    rightValid = right.MoveNext();  
} 

fullIList<T>のいくつかの並べ替えする必要があります:

+0

[Enumerable.Concat(Of TSource)メソッド](http://msdn.microsoft.com/en-us/library/bb302894.aspx)を再実装していませんか? –

+0

@Serge no、これはマージソートのマージ部分です。注 'if(* right <* left) ' – CodesInChaos

答えて

7

は、それはあなたのような何かをしたいように聞こえます。

は、ではありません。C++のような.NETイテレータを使用できるようにするための "ブリッジ"コードを作成してください。 .NETを使用しているときに.NETイテレータの観点から考え始める方がはるかに優れています。

.NETでイテレータを渡すことはほとんどありません。 IEnumerable<T>パラメータにあなたの方法を作るために、より自然で、とのようなものだろう:私は、MoveNextメソッド()、および現在のGetEnumeratorメソッド()したいと思います

using (IEnumerable<T> leftIterator = leftSequence.GetEnumerator()) 
{ 
    using (IEnumerable<T> rightIterator = rightSequence.GetEnumerator()) 
    { 
     // Code as above, just using leftIterator and rightIterator 
     // instead of left and right 
    } 
} 
+1

そして、.NETの列挙子は読み取り専用なので、' full'は反復子にはなりません。代わりに 'IList'のようなものを渡す必要があります。 –

+0

@MattiVirkkunen:確かに - それに注意してください。 –

+0

@CodeInChaos:申し訳ありません、はい、私は不変性についてのビットを明確にします。 .NETがイテレータのコピーを作成することをサポートしていないということをあなたが何を意味するのかよくわかりません.2つの 'IEnumerator 'を取り、それがうまくいくメソッドを作成できます。 'IEnumerable 'を取る方がいいでしょう。私はそれを編集します。 –

2

を。

通常、foreachを使用して反復することはできますが、あなたのケースは特別です。

"full"を使用するのではなく、これをイテレータブロックとして構成し、2つの列挙体を遅延してマージします。

IEnumerable<T> Merge<T>(IEnumerable<T> left, IEnumerable<T> right) 
{ 
    ... yield return Min<T>(left.Current, right.Current); .., 
} 
3

.netコンテナは、C++スタイルのイテレータをサポートしていません。

  • をコピーすることはできませんランダムアクセスではありません、彼らは

    • シンプル前方イテレータがコレクション
    • を変更することはできませんIEnumerator<T>
    • と呼ばれている唯一のものは、(いくつかのコレクションは、値の型を持っていますイテレータをコピーすることができ、それはトリッキーなビジネスとほとんど使用されません)です
    • ともあなたがコレクションを変更する時はいつでも無効になるほとんどのコレクションに

    彼らができる唯一の事は、foreachのステートメントで繰り返されています。


    あなたは、ランダムアクセスを許可しますが、唯一の高速インデックス作成をサポートするコレクションでサポートされていIList<T>インターフェイスに見たいと思うかもしれません。このようなコレクションでは、インデックスを使用してインプレースマージソートを実装できます。その後、

    void Merge<T>(IList<T> container,int left, int right, int leftEnd, int rightEnd, int full) 
    

    *leftの代わりにcontainer[left]を使用しています。


    残念なことに、C++のような効率的なインプレースコンテナに依存しない並べ替え機能を実装することはできません。

  • +0

    iteratorを、現在の位置を保持し、ナビゲーションを可能にするコレクションに対する便利なコンテナに依存しないハンドルとして定義すると、イテレータタイプの.NETのみが前方読み取り専用イテレータになります。これは残念です。多くの重要なアルゴリズムでは、双方向またはランダムアクセスのイテレータには多くの用途があります。 –

    0

    固定サイズの配列、またはList<T>(他の言語のArrayListsとも呼ばれます)を使用できます。アイテムにはインデクサー(list[i])でアクセスでき、アイテムにはlist.Add(item);を付けることができます。彼らは自動的に成長する。 LinkedListsはインデクサー経由ではアクセスできず、横断する必要があります。

    は、あなたが最も一般的なコレクション型によって実装され、この

    IEnumerable<int> intEnumerable = ...; 
    IEnumerator<int> intEnumerator = intEnumerable.GetEnumerator(); 
    

    IEnumerable<T>のように列挙子を取得することができ、この

    void merge(IEnumerator<int> left, IEnumerator<int> right, 
          List<int> full) 
    { 
        // Jon Skeet's code goes here 
    } 
    

    のようなメソッドを宣言します。一般的でないコレクションは通常IEnumerableを実装します。

    (@ CodeInChaosのコメントに対する反応で編集)

    +0

    'left' /' right'に渡すことができる列挙はありません。これらは部分的に反復されたイテレータのコピーです。 – CodesInChaos

    +0

    あなたの編集が問題を解決するとは思わない。これらのイテレータは、すべて同じコンテナ内の異なる要素を指している可能性があります。それらをインデックスのリストと考えてください。しかし、高速なインデックス作成をサポートしていないコレクションで作業してください。 – CodesInChaos

    +0

    'IEnumerator '( 'IEnumerable '!ではなく)**は**リスト内の一種のインデックスです。 'left'と' right'は同じコレクション内の異なる場所を指すことができます。 (私はそのタイプを 'IEnumerable 'から' IEnumerator 'に変更しました) –