2011-12-20 56 views
2

考慮使用一個循環來清空隊列中斯卡拉以下草圖:Scala:是否需要處理元組返回值的臨時變量?

var queue = immutable.Queue[T](/* .. some content ..*/) 
while(!queue.isEmpty) { 
    val (record, tempQueue) = queue.dequeue 
    queue = tempQueue 
    doSomethingWith(record) 
} 

有沒有辦法來避免臨時變量tempQueue並獲得斯卡拉返回隊列值直接分配給循環變量queue?不得不介紹額外的符號是煩人的,加上大概可能會有一些多餘的複製(儘管這可能會得到優化,不知道)。

編輯1:當然,作爲約努茨G.斯坦指出,我可以跳過模式匹配和拆開返回的對自己,如:

while(!queue.isEmpty) { 
    val pair = queue.dequeue 
    queue = pair._2 
    doSomethingWith(pair._1) 
} 

所以我應該改進的問題如下:有沒有辦法使用模式匹配的語法糖來更優雅地做到這一點?我希望這樣的事情,不幸的是不編譯:

var queue = immutable.Queue[T](/* .. some content ..*/) 
var record : A = _ 
while(!queue.isEmpty) { 
    (record, queue) = queue.dequeue 
    doSomethingWith(record) 
} 

回答

3

如果你堅持保留這個結構(在while循環等),我看不出你如何能使其更短,除非是:

var queue = immutable.Queue[T](/* some content */) 
while(!queue.isEmpty) queue.dequeue match { 
    case (record, tempQueue) => 
    queue = queue.dequeue 
    doSomethingWith(record) 
} 

由於您使用一個不變的隊列,但是,最簡單的等效代碼大概是:

for(record <- queue) { 
    doSomethingWith(record) 
} 

參見this related question這證實沒有辦法分配給預先存在var與模式匹配符號。

Scala Language Specification第4.1節也很清楚:模式匹配樣式分配擴展爲val定義,即它們將綁定一個新的標識符。

+0

上面這個SO的簡化例子的問題是,實際上你經常想做一些更復雜的事情,比如沒有完全排空隊列(在這種情況下,for循環將不起作用)。你提出的我猜想的匹配實際上等同於我所使用的代碼,它仍然使用臨時變量(我更新了我的問題以舉例說明我期望的內容:-)。我想答案可能是沒有辦法做到這一點,因爲我似乎無法將模式匹配結果提取到已經存在的變量中,只能將它們提取到新定義的變量中。 – 2011-12-20 14:35:06

+0

不幸的是,您提供的相關問題的鏈接似乎也是這個問題的(否定)答案。我會接受你的回答。謝謝! – 2011-12-20 14:39:48

1

可以使用_前綴的成員,提供最高達Tuple22

scala> val a = (1,2) 
a: (Int, Int) = (1,2) 

scala> a._1 
res0: Int = 1 

scala> a._2 
res1: Int = 2 
+0

謝謝,約努茨,這當然是正確的,但我希望有使用模式匹配方式以某種方式覆蓋已經存在的變量'queue'的值,同時爲'record'創建一個新的值。我擴展了這個問題並引用了你的答案。 – 2011-12-20 14:22:43

0

這裏是模式匹配,但它仍然引入了臨時變量。

while(!queue.isEmpty) { 
    queue = queue.dequeue match { 
    case (t: T, q: immutable.Queue[T]) =>  
     doSomethingWith(t) 
     q 
    } 
} 
2

您正在使用while循環和不可變的Queue。爲什麼不使用更多功能的方法(因爲無論如何你都擁有不變的Queue)?

您可以定義要在Queue中的每個項目上運行的功能,然後使用收集操作(根據您想要的回報來決定地圖等)來應用它。

E.G.

import scala.collection.immutable._ 

    val q = Queue[(Int,Int)]((1,2),(3,4),(5,6)) 

    def doSomethingWith(a:(Int,Int)) = { 
    a swap 
    } 

    //returns a new Queue with each tuple's elements swapped 
    q map doSomethingWith 

    //returns unit (so only useful if doSomethingWith has a side effect) 
    q foreach doSomethingWith 
+0

您是對的,這是處理整個隊列的更好方法。上面這些簡化例子的問題是,實際上我想做一些更復雜的事情,比如沒有完全排空隊列(在這種情況下map/clear不會很容易)。不過,這可能是一個選項,用謂詞對隊列進行分區,然後完全耗盡並映射其中一個分區。謝謝! – 2011-12-20 14:51:30

0

這裏有一個小黑客:

queue forall doSomethingWith 

假設doSomethingWith的類型是T => Boolean

2

不可變的數據結構,遞歸是FP的方式來做事。

def foo[T](queue: immutable.Queue[T]) { 
    if (!queue.isEmpty) { 
    val (record, remaining) = queue.dequeue 
    doSomethingWith(record) 
    foo(remaining) 
    } 
} 

foo(queue)是基本相同queue foreach doSomethingWith,其布萊恩史密斯建議。

+0

很整潔,謝謝! – 2011-12-21 13:28:59

0

根據條件,您可能可能首先過濾列表,或使用takeWhile,然後映射到結果集上。 喜歡的東西

(queue takeWhile condition) foreach operation 

(queue withFilter condition) foreach operation 

這隻能如果條件是單個元件的功能。 你也可以積累要與摺疊的部分(可能看起來像:)

(Nil /: queue)(<add element to accumulator if needed>) foreach operation 
相關問題