В языках программирования функций, таких как scala, каков подход, чтобы прекратить итерации по коллекции? Например; Вернуть true, если задано 0 - PullRequest
1 голос
/ 11 апреля 2020

В языках программирования функций, таких как scala, каков подход к прекращению итерации по коллекции? Например; Вернуть true, если задано 0.

Данный массив может иметь размер 100 с 0 в качестве первого элемента. Как этого добиться, используя чистую FP в scala?

При императивном подходе обычно это if (проверка на условие завершения) с последующим перерывом для остановки итерации.

Я новичок с FP & scala. Может кто-нибудь помочь в разъяснении?

Ответы [ 2 ]

2 голосов
/ 11 апреля 2020

Если вы посмотрите API-интерфейс List с, Set с, Vector с, Map с и т. Д. c, вы увидите множество таких утилит, как: reduce, fold, foldLeft, foldRight, map, et c.

Большинство функций предполагает, что вы можете вернуть результат только после обхода всей коллекции. Некоторые процессы обрабатываются только до тех пор, пока не будет выполнено условие, например, .takeWhile(cond) или не будут приняты только конкретные примеры, которые удовлетворяют условию, например, find(condition). Довольно часто случается, что то, что вы пытаетесь сделать с одним l oop, является комбинацией нескольких более простых функций, например:

var index = 0;
var result = 0;
// add all elements until first element bigger than 100
while (index < list.size) {
  if (list(index) > 100)
    break;
  index++;
  result += list(index);
}

может быть функционально выражено как:

list.takeWhile(i => i > 100).sum

Способность express к более сложным логикам c улучшится, поскольку вы будете изучать и использовать все больше и больше этих методов. Если вы не возражаете перебирать всю коллекцию, fold, reduce и т.п. обычно позволяют вам делать с вашими данными все, что вы хотите.

Однако, если вы все еще не знаете, как что-то реализовать Поскольку вам необходимо, например, отфильтровать, объединить и решить прекратить итерации, чтобы избежать n oop циклов, вы всегда можете вернуться к хвостовому рекурсивному вызову:

@scala.annotation.tailrec // annotation ensured that compiler will optimize body
def myOperation(unprocessedData: List[Int], resultSoFar: Int): Int =
  unprocessedData match {
    case head :: tail =>
      val newResult = resultSoFar + head
      myOperation(tail, newResult) // to enable tailrec instead of backtracking
                                   // you pass partial results as argument
                                   // and compiler will rewrite it underneath
                                   // into while with break
    case Nil =>
      resultSoFar                  // final result
  }

TL; DR

  • попробуйте использовать встроенные функции, такие как .map, .collect, .filter, .drop, .dropWhile, .take, .takeWhile для построения того, что вам нужно
  • , если слишком сложно попробуйте использовать fold, foldLeft, foldRight, reduce
  • , если все еще трудно, попробуйте использовать хвостовую рекурсию - это в основном более безопасная версия while - break, поэтому с этим вы всегда сможете реализовать то, что вы хотите
0 голосов
/ 12 апреля 2020

Вы можете использовать exists

Существует много типов неизменяемых коллекций, и они не наследуют exists от общего предка, но вы найдете его там разными способами.

Такой assert(List(0,1).exists(_ == 0))

Под капотом будет делать:

override final def exists(p: A => Boolean): Boolean = {
    var these: List[A] = this
    while (!these.isEmpty) {
      if (p(these.head)) return true
      these = these.tail
    }
    false
  }

или assert(scala.collection.immutable.ArraySeq(0,1).exists(_ == 0))

, что вызовет:

 def exists(p: A => Boolean): Boolean = {
    var res = false
    val it = iterator
    while (!res && it.hasNext) res = p(it.next())
    res
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...