2012-04-04 31 views
2

我正在編寫我的第一個Scala腳本來感受語言,而且我對於實現某些東西的最佳方式有點卡住了。處理未初始化的語言形式var

我的情況如下,我有一個方法,我需要調用N次,這個方法在每次運行時返回一個Int(可能不同,執行時有一個隨機組件),我想保留最佳運行(這些運行返回的最小值)。現在

,從Java/Python的背景的人,我只想初始化空/無變量,並在比較如果是這樣的:

best = None 
for... 
    result = executionOfThings() 
    if(best is None or result < best): 
     best = result 

而這是(原諒的半python僞代碼)。

現在,在斯卡拉,我掙扎了一下。我讀過有關選項和模式匹配,以達到同樣的效果的使用,我想我可以編寫了類似的信息(這是我能拿出最好的):

best match { 
    case None => best = Some(res) 
    case Some(x) if x > res => best = Some(res) 
    case _ => 
    } 

我相信這個作品,但我不確定它是否是寫作它最習慣的方式。這很明顯,但對於這樣一個簡單的「用例」有點冗長。

任何人都可以照亮我的功能燈?

謝謝。

+0

之後你想用'best'做什麼?這看起來像這個任務可以避免。你也可以利用'Option'的monadic屬性來使這個更簡潔一些。 – 2012-04-04 15:11:07

+0

將其返回/打印出來。最好的基本上是算法的結果。 – pcalcao 2012-04-04 15:12:00

+0

然後你可以使用'match'作爲表達式,而不是將它分配給某個東西。 – 2012-04-04 15:18:35

回答

1

對於這個特別是問題,不是一般的,我會建議初始化與Int.MaxValue只要你保證N >= 1。然後你只需

if (result < best) best = result 

,你也可以與best作爲一個選項,

best = best.filter(_ >= result).orElse(Some(result)) 

如果可選性是很重要的(例如,它可能是N == 0,你不採取不同的路徑通過在這種情況下的代碼)。這是處理可能被替換的可選值的更一般方式:使用filter保留未替換的案例,如果需要則使用orElse填充替換值。

+0

這似乎是我見過的最好的選擇。感謝您使用Option過濾器的解釋。 – pcalcao 2012-04-04 16:17:55

1

編輯:調整爲@用戶未知的建議

我建議你重新考慮你整個計算是更多的功能。你改變應該避免的狀態。我能想到的你的代碼的遞歸版本:

def calcBest[A](xs: List[A])(f: A => Int): Int = { 
    def calcBest(xs: List[A], best: Int = Int.MaxValue): Int = xs match { 
    // will match an empty list 
    case Nil => best 
    // x will hold the head of the list and rest the rest ;-) 
    case x :: rest => calcBest(rest, math.min(f(x), best)) 
    } 
    calcBest(xs) 
} 

調用與calcBest(List(7,5,3,8,2))(_*2) // => res0: Int = 4

有了這個,你有沒有可變狀態可言。

另一種方法是使用foldLeft名單:

list.foldLeft(Int.MaxValue) { case (best,x) => math.min(calculation(x),best) } 

foldLeft需要B和的Tuple2[B,A] => B一個PartialFunction並返回乙

這兩種方法是等效的。第一個可能更快,第二個更可讀。遍歷一個列表調用每個值的函數並返回最小值。你的代碼片段是你想要的,對吧?

+0

如果您可以將「計算」功能傳遞給該方法。也許,函數Any => Int或A => Int:'def calcBest [A](xs:List [A],f:(A => Int)):Int = {' – 2012-04-05 00:48:45

+0

是的,更好。我只是想舉個簡單的例子;-)。但我會調整它。 – drexin 2012-04-05 07:43:18

+0

謝謝你的更多功能的例子!我的情況並不完全涉及到對列表上的每個元素應用函數,調用完全相同,具有完全相同的參數,結果將因函數內部的隨機化而不同,但我認爲我可以適應,而您的例子一定會派上用場。 – pcalcao 2012-04-05 09:59:24

1

只需使用min函數:

(for (... executionOfThings()).min 

例子:

((1 to 5).map (x => 4 * x * x - (x * x * x))).min 
+0

這將遍歷第一個列表,建立一個新的列表並重復此過程。它會工作,但不是很高效。 – drexin 2012-04-04 17:15:04

+0

@drexin:我不明白你在說哪兩個表。聽起來像是過早的優化,如果它會處理一個真正的問題。 – 2012-04-04 17:25:28

+0

集合或其他...事情是,它將遍歷所有值2次。當你只有少量的值時,這並不重要。如果你能保證沒關係。但避免第二次遍歷並不難。 – drexin 2012-04-04 17:33:08

0

我想我會提供了另一種慣用的解決方案。您可以使用Iterator.continually來創建一個無限長度的迭代器,它被懶惰地評估,take(N)將迭代器限制爲N個元素,並使用min來查找獲勝者。

Iterator.continually { executionOfThings() }.take(N).min