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

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

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

3 ответа

Решение

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

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. Вид. Представление - это композиция операций над базовой коллекцией. При проверке представления каждый проверяемый элемент вычисляется по требованию. Это наиболее полезно, если вы будете иметь случайный доступ к представлению, но никогда не будете смотреть на него, кроме как на его небольшую часть. Например, выполнение кода ниже выведет "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 не поддерживает индексированный доступ (и представление будет работать плохо, если написано таким образом), и приведенный ниже код выводит "Вычисление 1", "Вычисление 2", "Вычисление 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))
    

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

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

У меня есть 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
Другие вопросы по тегам