私はScalaを初めて使いました。可能な限り最も基本的な知識でこれを表現するより良い方法がありますか?リストの最大値をスカラーで再帰的に見つける
def findMax(xs: List[Int]): Int = {
xs match {
case x :: tail => (if (tail.length==0) x else (if(x>findMax(tail)) x else (findMax(tail))))
}
}
私はScalaを初めて使いました。可能な限り最も基本的な知識でこれを表現するより良い方法がありますか?リストの最大値をスカラーで再帰的に見つける
def findMax(xs: List[Int]): Int = {
xs match {
case x :: tail => (if (tail.length==0) x else (if(x>findMax(tail)) x else (findMax(tail))))
}
}
ここでは2つの問題があります。まずを呼び出します。これはO(N)
の操作です。最悪の場合、これはN * N個のステップを必要とします。ここで、Nはシーケンスの長さです。もう1つは、関数が末尾再帰的ではないということです。findMax
を「外側から内側に」呼び出すことができます。
正しい再帰関数を記述するために通常の戦略は、それぞれの可能なパターンの場合について考えて
Nil
または非空のリストhead :: tail
のいずれかを持っています。これはあなたの最初の問題を解決します。これは与える:
import scala.annotation.tailrec
@tailrec
def findMax(xs: List[Int], max: Int): Int = xs match {
case head :: tail => findMax(tail, if (head > max) head else max)
case Nil => max
}
val z = util.Random.shuffle(1 to 100 toList)
assert(findMax(z, Int.MinValue) == 100)
あなたは、この追加の引数を公開したくない場合は、補助内部関数を書くことができます。
def findMax(xs: List[Int]): Int = {
@tailrec
def loop(ys: List[Int], max: Int): Int = ys match {
case head :: tail => loop(tail, if (head > max) head else max)
case Nil => max
}
loop(xs, Int.MinValue)
}
val z = util.Random.shuffle(1 to 100 toList)
assert(findMax(z) == 100)
簡略化のため、リストが空の場合はInt.MinValue
を返します。この場合、例外をスローする方がよい場合があります。
ここ@tailrec
注釈は、それは単に私たちが実際に末尾再帰関数を定義していることを保証し、オプションです。これは、リストが極端に長い場合にスタックオーバーフローを生成できないという利点があります。
空のリストは、Int.MinValueを生成します。これは、空でないInt.MinValuesのリストと同じです。 –
@userunknownはい、これは任意の選択です。 'if(xs.isEmpty)は新しいUnsupportedOperationException(" findMax(empty) ")'を投げることができます。三方向のパターンマッチについては、@ elmの答えも見てください。 –
コレクションを1つの値に減らす場合は、明示的な再帰の代わりにfoldのいずれかの関数を使用することを検討してください。再帰パターンマッチングを使用
List(3,7,1).fold(Int.MinValue)(Math.max)
// 7
ええ、これは良いアプローチですが、私はOPが再帰について学習しようとしていると思います。また、 'reduce(_ max _)'を使うと 'MinValue'は必要ありません。 – jwvh
'reduce'はOPの元のコードと同じ問題を抱えていますが、あなたは部分的な関数になります。 –
それから、 'reduceOption'を使うことができます。それは、コレクションが空であるかどうかを知りたいのか、またはリストかどうかにかかわらず、整数を持つだけであるかどうかによって異なります。 –
、
def top(xs: List[Int]): Int = xs match {
case Nil => sys.error("no max in empty list")
case x :: Nil => x
case x :: xs => math.max(x, top(xs))
}
パターンマッチングは、ヘッド、残りにリストを分解するために使用されます。 1つの要素リストはx :: Nil
と表示されます。リストの残りの部分について再帰的に反復し、各再帰的段階でリストの先頭項目の最大値を比較します。ケースを網羅的にするため(明確な関数を作るために)、空リスト(Nil
)も考慮します。
def maxl(xl: List[Int]): Int = {
if ((xl.head > xl.tail.head) && (xl.tail.length >= 1))
return xl.head
else
if(xl.tail.length == 1)
xl.tail.head
else
maxl(xl.tail)
}
こんにちはRahul、ソリューションを説明しようとすることができますし、他の答えよりも優れている理由は何ですか?この回答がアップ投票に値するかどうかは、他の人が判断するのに役立ちます。 –
@VlastimilOvčáčík私は自分のアプローチが他のものより優れているとは思わないが、私が与えたレスポンスはScalaの私の最初の段階に基づいていた(私はまだそれを学ぼうとしている)。今のところ私はChris Martinの答えが好きです。これはList(3,7,1).fold(Int.MinValue)(Math.max)です。 –
空リストを取得する場合は、Option(Int)を返す必要があります。 –