2

我有一个扩展迭代器并为复杂算法(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 的一步,然后运行 ​​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 interleaving 函数。很容易写一个

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
        }
    }
}

这构造了一个在两个流之间反复交替的流,从适当的流中获取下一个结果,然后为下一次获取设置它的状态。请注意,这种交错只适用于无限流,我们需要一个更聪明的来处理可以结束的流,但为了解决问题,这很好。

于 2010-06-27T23:19:13.827 回答
1

我有一个扩展迭代器并为复杂算法(MyAlgorithm1)建模的类。

好吧,停在那里一会儿。算法不是迭代器,因此扩展它没有意义Iterator

于 2010-06-27T18:36:56.560 回答
1

似乎您可能想要使用折叠或地图,具体取决于您想要做什么。这是函数式编程中的一种常见模式:您生成一个列表/序列/流,然后在每个元素上运行一个函数。如果要在每个元素上运行两个函数,可以组合函数或运行另一个映射。

于 2010-06-27T23:25:16.190 回答