Поток против просмотров против итераторов

В чем разница между потоками, представлениями (SeqView) и итераторами в scala? Это мое понимание:

  • Это все ленивые списки.
  • Потоки кэшируют значения.
  • Итераторы можно использовать только один раз? Вы не можете вернуться к началу и снова оценить значение?
  • Значения представления не кэшируются, но вы можете оценивать их снова и снова?

Итак, если я хочу сэкономить место в куче, должен ли я использовать итераторы (если я не буду снова просматривать список) или представления? Спасибо.


person JWC    schedule 01.03.2011    source источник
comment
stackoverflow.com/questions/4798043/ -------------- stackoverflow.com/questions /3361478/   -  person Gene T    schedule 05.03.2011


Ответы (1)


Во-первых, все они нестрогие. Это имеет особое математическое значение, связанное с функциями, но, по сути, означает, что они вычисляются по запросу, а не заранее.

Stream действительно ленивый список. Фактически, в Scala Stream — это List, а tail — это lazy val. После вычисления значение остается вычисленным и используется повторно. Или, как вы говорите, значения кэшируются.

Iterator можно использовать только один раз, потому что это указатель прохода в коллекцию, а не коллекция сама по себе. Что делает его особенным в Scala, так это тот факт, что вы можете применять преобразования, такие как map и filter, и просто получать новый Iterator, который будет применять эти преобразования только тогда, когда вы запрашиваете следующий элемент.

Scala раньше предоставляла итераторы, которые можно было сбросить, но это очень сложно поддерживать в общем виде, и они не сделали версию 2.8.0.

Представления предназначены для просмотра так же, как представление базы данных. Это ряд преобразований, которые применяются к коллекции для создания «виртуальной» коллекции. Как вы сказали, все преобразования применяются повторно каждый раз, когда вам нужно извлечь из него элементы.

И Iterator, и представления имеют отличные характеристики памяти. Stream хорош, но в Scala его главное преимущество заключается в написании бесконечных последовательностей (особенно последовательностей, определяемых рекурсивно). Однако можно избежать хранения всех Stream в памяти, убедившись, что вы не сохраняете ссылку на его head (например, используя def вместо val для определения Stream).

Из-за штрафов, налагаемых представлениями, обычно следует force их force после применения преобразований или оставить как представление, если ожидается, что когда-либо будет извлечено только несколько элементов по сравнению с общим размером представления.

person Daniel C. Sobral    schedule 01.03.2011
comment
Iterator также очень удобен для исследования бесконечности, и я обычно предпочитаю их потокам, где это возможно. Реальное преимущество потоков заключается в том, что ранее полученные значения кэшируются, что является серьезным преимуществом при попытке реализовать что-то вроде последовательности Фибоначчи, которая определяется в терминах предыдущих значений. - person Kevin Wright; 01.03.2011
comment
Фибоначчи — далеко не идеальный пример, поскольку ему нужны только два последних предыдущих значения, а сохранение всего потока — пустая трата времени. Функция Аккермана, вероятно, является каноническим примером. - person Jürgen Strobel; 21.09.2012
comment
@JürgenStrobel Ackermann приведет к плохой производительности, поскольку индексированный доступ к потокам равен O (n). Но я согласен с фибоначчи. - person Daniel C. Sobral; 23.09.2012
comment
О верно. Это делает Stream плохим выбором для любого подхода к кэшированию. - person Jürgen Strobel; 24.09.2012
comment
Не могли бы вы объяснить больше (например, используя def вместо val для определения Stream). эта часть? - person sasha.sochka; 20.04.2014
comment
scala› val x = {println(x); 1} x x: Int = 1 scala› x res17: Int = 1 scala› x res18: Int = 1 scala› def x = {println(x); 1} x: Int scala› x x res19: Int = 1 scala› x x res20: Int = 1 Таким образом, def снова работает, а val вычисляет один раз. - person dveim; 28.06.2014
comment
Этот ответ очень ясен, он должен быть частью документации ... о, на самом деле это так! Спасибо, Даниэль docs.scala-lang.org/tutorials/FAQ/ поток-представление-iterator.html - person Svend; 25.07.2014
comment
Вычисление простых чисел было бы лучшим приложением для Stream, потому что 1. все предыдущие значения (вплоть до квадратного корня) необходимы для вычисления следующего значения (эффективно) и 2. доступ наиболее эффективен, начиная с начала (поскольку более низкие значения являются более распространенными делителями исключить кандидаты на простые числа). - person combinatorist; 19.07.2019
comment
Как насчет объема памяти? например когда вы выполняете серию map в представлении/итераторе/потоке, все ли они создают временные коллекции в середине? - person texasbruce; 06.09.2019
comment
@texasbruce Я упоминаю об этом ближе к концу. Ни один из них не создает временные коллекции. Потоки сохранят все, на что у вас есть ссылка, поэтому, если вы сделаете val x = Stream.from(1).map(...).take(10), будет сохранен только окончательный результат. Если, с другой стороны, у вас есть val x = Stream.from(1); val y = x.map(...).take(10), то первое и последнее будут сохранены. - person Daniel C. Sobral; 17.09.2019