次のイテレーターがこのイテレーターより優れている点は何ですか?


8

私はJava / C#イテレータを直接操作することはあまりありませんが、「次の」方法でイテレータを設計する理由は何だろうといつも思っています。

開始するには、イテレータを移動する必要があります。データがあるかどうかを確認するには、次の要素があるかどうかを確認する必要があります。

私にとってより魅力的なコンセプトはthis-iteratorです。これは最初から「始まる」ので、この状態を確認できるとしましょうisValid。したがって、コレクション全体のループは次のようになります。

while (iter.isValid())
{
  println(iter.current());
  iter.next();
}

ここで次の要素があるかどうかを確認するために、そこに行き、状態が有効かどうかを確認します。

YMMVですが、とにかく-このイテレーターよりも次のイテレーター(Java / C#など)の利点はありますか?

注:これは、言語の設計に関する概念的な質問です。


質問はJavaまたはC#に対するものですbzoc isValidメソッドはJavaに存在しません

@NiksTyagi提案された設計はどちらの言語の実装とも異なるため、これは両方に等しく当てはまる概念的な質問です。
サービー2014

各仮想呼び出しにはコストがかかります。あなたの例には3つの呼び出しがあり、.netは2つだけです。個人的には、1回の通話に減らすことをお勧めします。
CodesInChaos 2014

回答:


6

MoveNext()JavaのhasNext()モデルに対するC#/。NETのモデルの利点は、前者はいくつかの作業が行われる可能性があることを意味することです。このhasNext()メソッドは、単純な状態チェックを意味します。しかし、遅延ストリームを反復していて、データベースにアクセスして結果があるかどうかを判断する必要がある場合はどうでしょうか。その場合、への最初の呼び出しhasNext()は、長いブロッキング操作になる可能性があります。hasNext()メソッドの命名は、実際に何が行われているのかについて非常に誤解を招く可能性があります。

実際の例では、この設計の問題は、JavaでMicrosoftのReactive Extensions(Rx)APIを実装するときに私に噛み付きました。具体的には、によって作成されたイテレータがIObservable.asIterable()適切に機能するために、hasNext()メソッドはブロックし、次のアイテム/エラー/完了通知が到着するのを待つ必要があります。それはほとんど直感的ではありません。名前は単純な状態チェックを意味します。MoveNext()遅延評価されたストリームを処理している場合は、ブロックする必要があるC#の設計とは対照的に、まったく予期しない結果にはなりません。

私のポイントはこれです。「this-iterator」モデルは嘘であることが多いため、「next-iterator」モデルは「this-iterator」モデルよりも望ましいです。チェックするために次の要素をプリフェッチする必要がある場合があります。イテレータの状態。私の意見では、その可能性を明確に伝えるデザインが望ましいと思います。はい、Javaの命名規則は「次の」モデルに従いますが、動作の影響は「this-iterator」モデルのそれに似ています。


明確化: Javaのモデルは欺瞞的であるため、おそらくJavaとC#の対比は不適切な選択でした。OPによって提示されたモデルの最も重要な違いは、「thisイテレータ」モデルが「is is valid」ロジックを「retrieve current / next element」ロジックから切り離し、理想的な「next-iterator」実装であると考えていますこれらの操作を組み合わせます。場合によっては、イテレータの状態が有効かどうかを判断するには次の要素をプリフェッチする必要があるため、それらを組み合わせることが適切であると考えています。

以下の間に設計上の大きな違いは見られません。

while (i.isValid()) { // do we have an element?  (implied as fast, non-blocking)
    doSomething(i.current()); // retrieve the element (may be slow!)
    i.next();
}
// ...and:
while (i.hasNext()) { // do we have an element?  (implied as fast, non-blocking)
    doSomething(i.next()); // retrieve the element (may be slow!)
}

しかし、私はここに意味のある違いを見ています:

while (i.hasNext()) { // do we have an element?  (implied as fast, non-blocking)
    doSomething(i.next()); // retrieve the element (may be slow!)
}
// ...and:
while (i.moveNext()) { // fetch the next element if it exists (may be slow!)
    doSomething(i.current()); // get the element  (implied as fast, non-blocking)
}

isValid()とのhasNext()例の両方で、高速かつ非ブロッキング状態のチェックであると暗黙的に示されている操作は、実際には低速のブロック操作である可能性があります。このmoveNext()例では、熱心に評価されたストリームと遅延評価されたストリームのどちらを処理しているかに関係なく、ほとんどの作業は期待どおりの方法で行われます。


1
+0:OPがJava / C#と他のイテレータを比較しようとしたと思います(C#IEnumrableとJava イテレータの両方が、作成時に「前」の要素を指します)。質問に対する私の理解は、C#とJavaを比較するのではなく、なぜ最初の要素を指さないのかということです。
アレクセイレベンコフ2014

回答ありがとうございます。ただし、C#とJavaは同じモデルを使用します(どちらも次の要素に重点を置いています)。
greenoldman 14

C#モデルとJavaモデルはまったく同じではありませ。追加した例を参照してください。C#のモデルは、要素の存在を確認する操作とその要素を取得する操作を組み合わせたものです。Javaはこれらを個別の操作に分割します。存在チェックでは、実際にアイテムを実際に取得する必要ある場合があります。これは、実際にはOPの例と非常によく似ています。メソッドの名前を無視すると、にhasNext()似てisValid()おり、next()に似ていcurrent()ます。
マイクストロベル14

この質問の意味でのモデルを意味しました。OK、それらは同一ではありませんが、どちらも次の要素に基づいています。両方で反復する場合、両方とも実際のコレクションの前に開始するため、開始時に次の要素に移動する必要があります。
greenoldman 14

私は、Javaモデル、実際にどのように機能するかという問題の「this-iterator」モデル非常に似ていると主張します。「this-iterator」と「next-iterator」の間の動作の影響は命名規則よりも重要であり、Javaモデルには「this-iterator」の例と同様の動作の影響があると私は主張します。私の回答がOPが質問をする際に考慮しなかった領域に迷い込んだ可能性がありますが、それが私の回答の有効性を低下させるとは思いません。
Mike Strobel、2014

7

各値を計算するために実行する必要がある計算がある場合、最初の値を要求する前に次の値を取得する必要がある場合は、イテレーターの構築を超えてその最初の値の処理を延期できます。

たとえば、イテレータはまだ実行されていないクエリを表すことができます。最初の項目が要求されると、データベースに結果が照会されます。提案された設計を使用して、その計算はイテレータの構築時に実行する必要があります(これにより、実行の延期が難しくなります)またはを呼び出すIsValid場合、呼び出しIsValidは実際には次の値を取得するため、実際には誤った名前になります。


いい答えだ。あなたは私と同じポイントをヒットしましたが、数秒で私を倒しました。賛成投票してください:)
マイクストロベル14

1
答えてくれてありがとうございますが、間違いだと思います。イテレータが有効かどうかを確認するには、実際の要素を取得する必要はなく、イテレータの位置を取得するだけです。IOWはと同じ影響がありますが、hasNext現在の状態に関する状態のみであり、将来の状態ではありません。または別の見方をすると、これをC ++イテレータと比較して、(current!=end)実際のデータに触れずに状態が有効かどうかを確認します。
greenoldman 14

PS。あなたのシナリオに固執しましょう-結果を印刷したいのでhasNext、最初に呼び出す必要があります。ここでクエリが実行され、データが取得されます。2番目のモデルではを呼び出しisValidます。ここでクエリが実行されます。したがって、クエリ実行のポイントは同じです。
greenoldman 14

@greenoldmanつまり、IsValid実際に行っていることを呼び出すと、次の値が取得されます。これは、既存のイテレータとまったく同じことをしていることを意味します(最初から現在の有効性がなく、取得するためにメソッドを呼び出す必要がない)。
サービー

1
丁度。「this-iterator」モデルは嘘であることが多いため、「this-iterator」モデルよりも「next-iterator」モデルの方が適しています。イテレータの状態を確認するために、次の要素をプリフェッチする必要がある場合があります。 。
マイクストロベル14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.