2010-06-27 92 views
2

我有一個擴展Iterator併爲一個複雜算法(MyAlgorithm1)建模的類。因此,算法可以通過Next方法逐步推進。混合算法

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

現在我想在第一個算法的每次通過中應用不同的算法(MyAlgorithm2)。應該插入算法1和2的迭代

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

我該如何以最好的方式做到這一點?也許有一些特質?

UPDATE:

MyAlgorithm2收到
一套,改造它。 MyAlgorithm1也是如此,但這更復雜,需要一步一步的運行。這個想法運行MyAlgoirthm1的一個步驟,然後運行MyAlgorithm2。下一步同樣。真的,MyAlgorithm2簡化了這個集合,可能對簡化MyAlgorithm1的工作很有用。

+0

如果你嘗試要更具體地說明你想做什麼,我們可能會想出一個有用的答案。 – mkneissl 2010-06-27 19:23:21

+0

mkneissl,我希望更好地解釋 – barroco 2010-06-27 19:44:16

+0

isola009,我不明白你想如何將MyAlg1加入MyAlg2。您是否將第一個算法的結果傳遞給第二個算法的輸入或反之亦然或交錯結果? – 2010-06-28 03:22:20

回答

1

我有一個類擴展了Iterator併爲一個複雜的算法(MyAlgorithm1)建模。

好吧,停下來一會兒。一個算法不是一個迭代器,所以它延長Iterator沒有意義。

+0

這是不爭的事實。我需要對算法進行建模,以便它可以一步一步地運行。 – barroco 2010-06-27 19:00:07

2

擴展迭代器可能比你實際需要做的更多的工作。讓我們回滾一下。

你已經有了類的一些狀態的對象MyAlgorithm1

val alg1 = new MyAlgorithm1(args) 

現在要反覆調用它的一些功能,這將改變它的狀態,並返回一定的價值。這最好不是通過讓對象實現迭代器來建模,而是通過創建一個處理迭代的新對象。可能是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 
} 

可悲的是,通過標準庫中快速瀏覽,顯示沒有流交織功能。易足夠寫一個

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

對構造交替反覆兩股之間,從適當的一個獲取下一個結果,然後下次提取設置它的狀態流。請注意,這種交錯只適用於無限流,我們需要一個更聰明的處理可能結束的流,但這對問題的好處很好。

+0

對於任何數量的流並且不使用var都有更好的方法。但是,是的 – 2013-05-18 21:37:07

1

看起來好像您可能想要使用摺疊或地圖,具體取決於您想要做什麼。這是函數式編程中的一種常見模式:您可以生成某個列表/序列/數據流,然後在每個元素上運行一個函數。如果你想在每個元素上運行兩個函數,你可以編寫函數或運行另一個地圖。

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)