算法混合

时间:2010-06-27 17:09:09

标签: scala traits

我有一个扩展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的一步,然后运行MyAlgorithm2。下一步一样。实际上,MyAlgorithm2简化了集合,可能有助于简化MyAlgorithm1的工作。

4 个答案:

答案 0 :(得分: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)

答案 1 :(得分: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交错功能。很容易写一个

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 :(得分:1)

  

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

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

答案 3 :(得分:1)

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