2013-05-19 50 views
0

我正在編寫一個模擬程序,其中一些操作員從一個隊列中取得工作。在每個時間步驟中,我需要依次檢查序列的元素,並且如果條件通過,則用隊列中的項目替換當前值。必須保留隊列中的剩餘部分以供後續迭代使用。使用隊列的修補程序序列

我寫過一個叫做patch的程序來做到這一點,但它看起來並不是很整齊。有沒有一種更習慣的方式來實現同樣的目標?我希望它速度相當快,但仍然保持功能。

import scala.annotation.tailrec 
import scala.collection.immutable.Queue 

object SeqPimp extends App{ 

    val mySeq = Seq('a', 'B', 'C', 'd', 'E') 
    val shortQ = Queue('+','-') 
    val longQ = Queue('+','-','*','/','%') 

    println(patch(mySeq)(_.isUpper, shortQ)) 
    //Output: (List(a, +, -, d, E),Queue()) 

    println(patch(mySeq)(_.isUpper, longQ)) 
    //Output: (List(a, +, -, d, *),Queue(/, %)) 

    def patch[T](to: Seq[T])(condition: T => Boolean, from: Queue[T]): (Seq[T], Queue[T]) = { 
     @tailrec 
     def go(acc: Seq[T], remaining: Seq[T], q: Queue[T]): (Seq[T], Queue[T]) = { 
      if(acc.size == to.size) (acc.reverse, q) 
      else if(q.size == 0) (acc.reverse ++: remaining, q) 
      else{ 
       if(condition(remaining.head)){ 
        val (item, q1) = q.dequeue 
        go(item +: acc, remaining.tail, q1) 
       }else{ 
        go(remaining.head +: acc, remaining.tail, q) 
       } 
      } 
     } 

     go(Nil, to, from) 
    } 
} 

回答

1

Prolly這樣的事情...

def patch[T](to: Seq[T])(condition: T => Boolean, from: Queue[T]): (Seq[T], Queue[T]) = { 
if (from.isEmpty) (to, from) 
else { 
    val i = to.indexWhere(condition) 
    if (i == -1) (to, from) 
    else patch(to.patch(i, Seq(from.head), 1))(condition, from.tail) 
} 
} 

或者你可以簡單地豐富SEQ這樣..

object SeqPimp extends App { 

    implicit class EnSeq[T](val to: Seq[T]) extends AnyVal{ 
    def enPatch(condition: T => Boolean, from: Queue[T]): (Seq[T], Queue[T]) = { 
     if (from.isEmpty) (to, from) 
     else { 
     val i = to.indexWhere(condition) 
     if (i == -1) (to, from) 
     else to.patch(i, Seq(from.head), 1).enPatch(condition, from.tail) 
     } 
    } 
    } 

    val mySeq = Seq('a', 'B', 'C', 'd', 'E') 
    val shortQ = Queue('+', '-') 
    val longQ = Queue('+', '-', '*', '/', '%') 

    mySeq.enPatch(_.isUpper, shortQ) 
    //Output: (List(a, +, -, d, E),Queue()) 

    mySeq.enPatch(_.isUpper, longQ) 
    //Output: (List(a, +, -, d, *),Queue(/, %)) 

} 

編輯

這裏是def patch與更好的表現..但不像以前漂亮..

def patch[T](to: Seq[T])(condition: T => Boolean, from: Queue[T]): (Seq[T], Queue[T]) = { 
    @tailrec 
    def go(acc: Seq[T], remaining: Seq[T], q: Queue[T]): (Seq[T], Queue[T]) = { 
     if (q.isEmpty || remaining.isEmpty) (acC++ remaining, q) 
     else { 
     val (accu, rem) = remaining.span(e => !condition(e)) 
     if (rem.isEmpty) (acC++ accu, q) 
     else go(acC++ accu.:+(q.head), rem.tail, q.tail) 
     } 
    } 
    go(Nil, to, from) 
    } 
+0

這似乎更清潔,只是一個恥辱,似乎慢了大約30%,我猜這是因爲索引訪問額外的遍歷。奇怪的是,將輸入切換到IndexedSeq將速度差距擴大到〜50%。 – Pengin

+1

是的,性能很差。嘗試用'to.updated(i,from.head)'替換'to.patch(i,Seq(from.head),1)'..如果它更好。 。lemme知道..將編輯答案 – Shrey

+1

編輯運行時間不到我原來的一半,而且行數也少!花了一些時間思考,看看爲什麼它更快。前瞻是很好的技巧。 – Pengin

相關問題