Можно ли использовать «yield» для генерации «Итератора» вместо списка в Scala? - PullRequest
28 голосов
/ 24 декабря 2010

Можно ли использовать yield в качестве итератора без оценки каждого значения?

Это обычная задача, когда легко реализовать создание сложного списка, а затем вам нужно преобразовать его в Iterator, потому что вам не нужны некоторые результаты ...

Ответы [ 3 ]

49 голосов
/ 24 декабря 2010

Конечно.На самом деле, есть три варианта нестрогости, которые я перечислю ниже.Для примеров предположим:

val list = List.range(1, 10)
def compute(n: Int) = {
    println("Computing "+n)
    n * 2
}
  1. Stream.Stream - лениво оцененный список.Он будет вычислять значения по требованию, но не будет пересчитывать значения после их вычисления.Это наиболее полезно, если вы будете многократно использовать части потока.Например, при выполнении приведенного ниже кода будут выводиться «Computing 1», «Computing 2» и «Computing 3», по одному разу.

    val stream = for (n <- list.toStream) yield compute(n)
    val third = stream(2)
    println("%d %d" format (third, stream(2)))
    
  2. A view .Представление - это композиция операций над базовой коллекцией.При проверке представления каждый проверяемый элемент вычисляется по требованию.Это наиболее полезно, если вы будете иметь случайный доступ к представлению, но никогда не будете смотреть на него, кроме как на его небольшую часть.Например, выполнение кода ниже выведет «Computing 3» два раза, и ничего больше (ну, кроме результата).

    val view = for (n <- list.view) yield compute(n)
    val third = view(2)
    println("%d %d" format (third, view(2)))
    
  3. Iterator.Iterator - это то, что используется для ленивой прогулки по коллекции.Можно сказать, что это «одноразовая» коллекция, так сказать.Он не будет ни пересчитывать, ни хранить какие-либо элементы - после того, как элемент был «вычислен», он не может быть снова использован.Из-за этого его немного сложнее использовать, но он наиболее эффективен с учетом этих ограничений.Например, следующий пример должен отличаться, потому что Iterator не поддерживает индексированный доступ (и представление будет работать плохо, если написано таким образом), а код ниже выдает «Computing 1», «Computing 2», «Computing 3».»,« Вычисление 4 »,« Вычисление 5 »и« Вычисление 6 ».Кроме того, он печатает два разных числа в конце.

    val iterator = for (n <- list.iterator) yield compute(n)
    val third = iterator.drop(2).next
    println("%d %d" format (third, iterator.drop(2).next))
    
3 голосов
/ 24 декабря 2010

Используйте представления, если вы хотите ленивую оценку, см. Просмотры .

API коллекций Scala 2.8 - фантастическое чтение, если вы собираетесь много использовать коллекции Scala.

2 голосов
/ 24 декабря 2010

У меня есть List ...

scala>  List(1, 2, 3)
res0: List[Int] = List(1, 2, 3)

И функция ...

scala> def foo(i : Int) : String = { println("Eval: " + i); i.toString + "Foo" }
foo: (i: Int)String

А теперь я буду использовать для понимания с Iterator ...

scala> for { i <- res0.iterator } yield foo(i)
res2: Iterator[java.lang.String] = non-empty iterator

Вы можете использовать для понимания любого типа с flatMap, map и filter методами.Вы также можете использовать views :

scala> for { i <- res0.view } yield foo(i)
res3: scala.collection.SeqView[String,Seq[_]] = SeqViewM(...)

Оценка не является строгой в любом случае ...

scala> res3.head
Eval: 1
res4: String = 1Foo
...