2

Iteratorを拡張し、複雑なアルゴリズム(MyAlgorithm1)をモデル化するクラスがあります。したがって、アルゴリズムはNextメソッドを段階的に進めることができます。

class MyAlgorithm1(val c:Set) extends Iterator[Step] {
   override def next():Step {
       /* ... */
   }
   /* ... */
}

ここで、最初のアルゴリズムの各パスに異なるアルゴリズム(MyAlgorithm2)を適用します。アルゴリズム1と2の反復を挿入する必要があります

class MyAlgorithm2(val c:Set) { /* ... */ }

どうすればこれを最善の方法で行うことができますか?おそらくいくつかの特性がありますか?

アップデート:

MyAlgorithm2はセットを受け取り、それを変換します。MyAlgorithm1もありますが、これはより複雑であり、段階的に実行する必要があります。アイデアは、MyAlgoirthm1の1つのステップを実行してから、MyAlgorithm2を実行します。次のステップも同じです。実際、MyAlgorithm2はセットを単純化し、MyAlgorithm1の作業を単純化するのに役立つ場合があります。

4

4 に答える 4

4

説明したように、問題は継承または特性のいずれかで解決できます。例えば:

class MyAlgorithm1(val c:Set) extends Iterator[Step] {
  protected var current = Step(c)
  override def next():Step = {
    current = process(current)
    current 
  }
  override def hasNext: Boolean = !current.set.isEmpty
  private def process(s: Step): Step = s
}

class MyAlgorithm2(c: Set) extends MyAlgorithm1(c) {
  override def next(): Step = {
    super.next()
    current = process(current)
    current
  }
  private def process(s: Step): Step = s
}

トレイトを使用して で何かを行うこともできますがabstract override、単純化の結果が最初のアルゴリズムに渡されるように設計するのは難しいかもしれません。

しかし、あなたが間違った方法で問題に取り組んでいることを提案させてください。

イテレータを拡張するアルゴリズムのクラスを作成する代わりに、次のようにアルゴリズムを定義できます。

class MyAlgorithm1 extends Function1[Step, Step] {
  def apply(s: Step): Step = s
}

class MyAlgorithm2 extends Function1[Step, Step] {
  def apply(s: Step): Step = s
}

イテレータは、はるかに簡単に定義できます。

Iterator.iterate(Step(set))(MyAlgorithm1 andThen MyAlgorithm2).takeWhile(_.set.nonEmpty)
于 2010-06-28T01:15:10.950 に答える
2

Iterator の拡張は、おそらく実際に必要な作業よりも多くの作業です。少しロールバックしましょう。

タイプ MyAlgorithm1 のステートフル オブジェクトがあります。

val alg1 = new MyAlgorithm1(args)

ここで、状態を変更して何らかの値を返す関数を繰り返し呼び出したいとします。これは、オブジェクトに Iterator を実装させるのではなく、反復を処理する新しいオブジェクトを作成することによってモデル化するのが最適です。Scala 標準ライブラリでおそらく最も簡単なのは Stream です。これは、アルゴリズムから結果のストリームを作成するオブジェクトです。

val alg1Stream:Stream[Step] = Stream.continually(alg1.next())

そのストリームから繰り返し結果を取得したい場合は、次のように簡単です

for(step<-alg1Stream){
   // do something
}

または同等に

alg1Stream.forEach{
    //do something
}

ここで、myAlgorithm2 もストリームとしてカプセル化したとします。

val alg2=new MyAlgorithm2(args)
val alg2Stream:Stream[Step] = Stream.continually(alg2.next())

次に、ストリームをインターリーブする方法が必要です。

for(step<-interleave(alg1Stream, algStream2)){
   // do something
}

悲しいことに、標準ライブラリをざっと見てみると、Stream インターリーブ機能がないことがわかります。簡単に1つ書ける

def interleave[A](stream1:Stream[A], stream2:Stream[A]):Stream[A] ={
    var str1 = stream1
    var str2 = stream2
    var streamToUse = 1
    Stream.continually{
        if(streamToUse == 1){
           streamToUse = 2
           val out = str1.head
           str1 = str1.tail
           out
        }else{
           streamToUse = 1
           val out = str2.head
           str2 = str1.tail
           out
        }
    }
}

これにより、2 つのストリームを交互に繰り返し使用するストリームが構築され、適切な結果から次の結果がフェッチされ、次のフェッチのためにその状態が設定されます。このインターリーブは無限ストリームに対してのみ機能することに注意してください。終了する可能性のあるストリームを処理するには、より賢いものが必要ですが、問題のためにはそれで問題ありません。

于 2010-06-27T23:19:13.827 に答える
1

Iteratorを拡張し、複雑なアルゴリズム(MyAlgorithm1)をモデル化するクラスがあります。

さて、そこでちょっと立ち止まってください。アルゴリズムはイテレータではないため、を拡張しても意味がありませんIterator

于 2010-06-27T18:36:56.560 に答える
1

正確に何をしたいのかによって、代わりにフォールドまたはマップを使用したい場合があるようです。これは関数型プログラミングの一般的なパターンです。何かのリスト/シーケンス/ストリームを生成し、各要素に対して関数を実行します。各要素で 2 つの関数を実行する場合は、関数を作成するか、別のマップを実行できます。

于 2010-06-27T23:25:16.190 に答える