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

Можно ли использовать 'yield' для генерации 'Iterator' вместо списка в Scala?

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

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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

Ответ 3

У меня есть 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. Вы также можете использовать представления:

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

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

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