2012-04-04 15 views
2

私は最初のScalaスクリプトをコーディングして、言語を感じています。何かを達成するための最良の方法についてちょっと固まっています。初期化されていない変数を扱う慣習的な形式

私はN回呼び出す必要のあるメソッドを持っていますが、このメソッドは実行ごとにIntを返します(実行にはランダムなコンポーネントがあります)。最善の実行(これらの実行で返される最小値)。今

、Javaの/ Pythonの背景から来て、私は単にヌル/なしで変数を初期化し、場合に比較し、のようなものでしょう:

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

そして、それは半ため(その恩赦ですPythonの擬似コード)。

今、Scalaでは、少し苦労しています。私は、同じ効果を達成するためのマッチングオプションとパターンの使用方法については読んだ、と私は(これは私が思い付くことができる最高だった)のような何かをコーディングすることができると思います:

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

私は、この作品と信じてしかし、それがそれを書いている最も慣用的な方法であるかどうかはわかりません。それは十分にはっきりしていますが、このようなシンプルな「ユースケース」については少し冗長です。

私に機能的な光を照らすことができる人は誰ですか?

ありがとうございました。

+0

後で「ベスト」と何をしたいですか?この割り当ては避けることができるように見えます。おそらく、これをもう少し簡潔にするために、 'Option'のモナド性を利用することもできます。 –

+0

それを返す/それを印刷する。最高は基本的にアルゴリズムの結果です。 – pcalcao

+0

'match'を式に代入するだけで、何かに代入するのではなくて使うことができます。 –

答えて

1

特にの問題ですが、一般的には、N >= 1が保証されている限り、Int.MaxValueで初期化することをおすすめします。次に、あなただけの

if (result < best) best = result 

あなたは可能性も、オプションとしてbest

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

との選択性が重要な場合(例えば、それはそのN == 0可能であり、あなたが通過に異なるパスを取ることはありませんその場合のコード)。交換される可能性のあるオプションの値を扱うより一般的な方法です。置き換えられない場合はfilterを使用し、必要な場合はorElseを使用して補充します。

+0

これは私が見た最良の選択肢のようです。オプション付きフィルターの使用についての説明をありがとうございます。 – pcalcao

1

編集:@ユーザー-不明の提案に調整が

私はあなたがより機能的であることをあなたに全体の計算を再考することをお勧め。あなたは避けるべき状態を変更します。あなたは全く変更可能な状態を持っていません。これによりcalcBest(List(7,5,3,8,2))(_*2) // => res0: Int = 4

で呼び出し可能

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

:私はあなたのコードの再帰バージョンを考えることができます。

もう一つの方法は、リスト上のfoldLeftを使用することです:

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

foldLeftはBとTuple2[B,A] => Bの部分写像を取り、どちらの方法が等価であるB

を返します。最初の方がおそらく速く、2番目の方が読みやすくなります。両方とも、リスト呼び出しを各値の関数でトラバースし、最小値を返します。あなたのスニペットからあなたが望むのはどちらですか?

+0

メソッドに '計算'関数を渡すことができます。たぶん、関数Any => IntまたはA => Int: 'def calcBest [A](xs:List [A]、f:(A => Int)):Int = {' –

+0

より一般的には、より良い。私はちょうどよい例を与えたいと思った;-)。しかし、私はそれを調整します。 – drexin

+0

もっと機能的な例をありがとう!私のケースでは、リストの各要素に関数を適用することはまったく関係しません。呼び出しはまったく同じ引数で、関数内のランダム化によって結果は異なりますが、私は適応できると思います例は確かに便利でしょう。 – pcalcao

1

だけ分の機能を使用します。

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

例:

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

最初のリストを反復し、新しいリストを作成し、それを繰り返します。それはうまくいくだろうが、あまり効果がない。 – drexin

+0

@drexin:あなたが話している2つのリストを理解できません。本当の問題に対処するならば、早すぎる最適化のように聞こえるでしょう。 –

+0

コレクションなど何か...ということは、すべての値を2回トラバースすることです。少量の値しか持たない場合、これは重要ではありません。それが大丈夫だと保証できるならば。しかし、2回目のトラバースを避けることは難しくありません。 – drexin

0

私は別の慣用的なソリューションを提供するだろうと思いました。 Iterator.continuallyを使用して、遅延評価の無限長イテレータ、反復子をN要素に制限するtake(N)を作成し、minを使用して勝者を見つけることができます。

Iterator.continually { executionOfThings() }.take(N).min 
関連する問題