Подтвердить что ты не робот

Найти минимальные и максимальные элементы массива

Я хочу найти минимальные и максимальные элементы массива, используемые для понимания. Можно ли сделать это с помощью одной итерации массива, чтобы найти как элемент min, так и max?

Я ищу решение без использования scala при условии array.min или max.

4b9b3361

Ответ 1

Вот краткое и читаемое решение, которое позволяет избежать уродливых операторов 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

Вы можете получить минимальные и максимальные значения массива [Int] с помощью функции reduceLeft.

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

Ответ 3

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

Ответ 4

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
}

Ответ 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, что делает функцию менее общей).

Ответ 6

Рассмотрим это (для непустых упорядочиваемых массивов),

val ys = xs.sorted
val (min,max) = (ys.head, ys.last)

Ответ 7

Я очень опаздываю на вечеринку по этому поводу, но я новичок в Scala и думал, что буду участвовать в любом случае. Вот решение, использующее рекурсию хвоста:

@tailrec
def max(list: List[Int], currentMax: Int = Int.MinValue): Int = {
    if(list.isEmpty) currentMax
    else if ( list.head > currentMax) max(list.tail, list.head)
    else max(list.tail,currentMax)
}

Ответ 8

Вы всегда можете написать свою собственную функцию 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

Ответ 9

Из всех ответов, которые я рассмотрел на эти вопросы, ДНК-решение было наиболее близким к "Scala idiomatic", которое я мог найти. Тем не менее, это может быть немного улучшено...:

  1. Выполнение как можно меньшего количества сравнений (важно для очень больших коллекций)
  2. Обеспечьте идеальную последовательность заказа, используя только метод Ordering.lt
  3. Избежание исключения
  4. Сделать код более читабельным для новичков и изучающих Scala

Комментарии должны помочь прояснить изменения.

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