我想使用for comprehension找到数组的min和max元素。是否可以通过一次迭代的数组来找到min元素和max元素?
我正在寻找一种解决方案,而不使用scala提供的array.min或max。
答案 0 :(得分:48)
您可以使用reduceLeft
函数获取Array [Int]的最小值和最大值。
scala> val a = Array(20, 12, 6, 15, 2, 9)
a:数组[Int] =数组(20,12,6,15,2,9)
scala> a.reduceLeft(_ min _)
res:Int = 2
scala> a.reduceLeft(_ max _)
res:Int = 20
有关reduceLeft
方法的更多信息和示例,请参阅此链接:http://alvinalexander.com/scala/scala-reduceleft-examples
答案 1 :(得分:21)
这是一个简洁易读的解决方案,可以避免丑陋的if
语句:
def minMax(a: Array[Int]) : (Int, Int) = {
if (a.isEmpty) throw new java.lang.UnsupportedOperationException("array is empty")
a.foldLeft((a(0), a(0)))
{ case ((min, max), e) => (math.min(min, e), math.max(max, e))}
}
说明:foldLeft
是Scala中许多集合的标准方法。它允许将累加器传递给将为数组的每个元素调用的回调函数。
请查看scaladoc了解更多详情
答案 2 :(得分:6)
def findMinAndMax(array: Array[Int]) = { // a non-empty array
val initial = (array.head, array.head) // a tuple representing min-max
// foldLeft takes an initial value of type of result, in this case a tuple
// foldLeft also takes a function of 2 parameters.
// the 'left' parameter is an accumulator (foldLeft -> accum is left)
// the other parameter is a value from the collection.
// the function2 should return a value which replaces accumulator (in next iteration)
// when the next value from collection will be picked.
// so on till all values are iterated, in the end accum is returned.
array.foldLeft(initial) { ((min, max), x) =>
if (x < min) (x, max)
else if (x > max) (min, x)
else acc
}
}
答案 3 :(得分:5)
val xs: Array[Int] = ???
var min: Int = Int.MaxValue
var max: Int = Int.MinValue
for (x <- xs) {
if (x < min) min = x
if (x > max) max = x
}
答案 4 :(得分:5)
继续其他答案之后 - 可以使用更通用的解决方案,该解决方案适用于其他集合以及Array
,以及其他内容以及Int
:
def minmax[B >: A, A](xs: Iterable[A])(implicit cmp: Ordering[B]): (A, A) = {
if (xs.isEmpty) throw new UnsupportedOperationException("empty.minmax")
val initial = (xs.head, xs.head)
xs.foldLeft(initial) { case ((min, max), x) =>
(if (cmp.lt(x, min)) x else min, if (cmp.gt(x, max)) x else max) }
}
例如:
minmax(List(4, 3, 1, 2, 5)) //> res0: (Int, Int) = (1,5)
minmax(Vector('Z', 'K', 'B', 'A')) //> res1: (Char, Char) = (A,Z)
minmax(Array(3.0, 2.0, 1.0)) //> res2: (Double, Double) = (1.0,3.0)
(也可以使用cmp.min()
和cmp.max()
更简洁地写这一点,但前提是你删除B >: A
类型绑定,这会使函数不那么通用。)< / p>
答案 5 :(得分:0)
您总是可以编写自己的foldLeft
函数 - 这将保证一次迭代和已知性能。
val array = Array(3,4,62,8,9,2,1)
if(array.isEmpty) throw new IllegalArgumentException // Just so we can safely call array.head
val (minimum, maximum) = array.foldLeft((array.head, array.head)) { // We start of with the first element as min and max
case ((min, max), next) =>
if(next > max) (min, next)
else if(next < min) (next, max)
else (min, max)
}
println(minimum, maximum) //1, 62
答案 6 :(得分:0)
在我对此问题的所有回答中,DNA的解决方案是我所能找到的最接近“惯用的斯卡拉”的解决方案。但是,可以通过...进行一些改进:
评论应有助于阐明更改。
def minAndMax[B>: A, A](iterable: Iterable[A])(implicit ordering: Ordering[B]): Option[(A, A)] =
if (iterable.nonEmpty)
Some(
iterable.foldLeft((iterable.head, iterable.head)) {
case (minAndMaxTuple, element) =>
val (min, max) =
minAndMaxTuple //decode reference to tuple
if (ordering.lt(element, min))
(element, max) //if replacing min, it isn't possible max will change so no need for the max comparison
else
if (ordering.lt(max, element))
(min, element)
else
minAndMaxTuple //use original reference to avoid instantiating a new tuple
}
)
else
None
这是扩展使用单次返回二维空间上下限的解决方案,再次使用上述优化方法:
def minAndMax2d[B >: A, A](iterable: Iterable[(A, A)])(implicit ordering: Ordering[B]): Option[((A, A), (A, A))] =
if (iterable.nonEmpty)
Some(
iterable.foldLeft(((iterable.head._1, iterable.head._1), (iterable.head._2, iterable.head._2))) {
case ((minAndMaxTupleX, minAndMaxTupleY), (elementX, elementY)) =>
val ((minX, maxX), (minY, maxY)) =
(minAndMaxTupleX, minAndMaxTupleY) //decode reference to tuple
(
if (ordering.lt(elementX, minX))
(elementX, maxX) //if replacing minX, it isn't possible maxX will change so no need for the maxX comparison
else
if (ordering.lt(maxX, elementX))
(minX, elementX)
else
minAndMaxTupleX //use original reference to avoid instantiating a new tuple
, if (ordering.lt(elementY, minY))
(elementY, maxY) //if replacing minY, it isn't possible maxY will change so no need for the maxY comparison
else
if (ordering.lt(maxY, elementY))
(minY, elementY)
else
minAndMaxTupleY //use original reference to avoid instantiating a new tuple
)
}
)
else
None
答案 7 :(得分:0)
scala> val v = Vector(1,2)
scala> v.max
res0: Int = 2
scala> v.min
res1: Int = 2
您可以使用min
的{{1}}和max
方法