У меня есть Scala Iterator
(я могу использовать любой тип данных для своей цели), который я нарисовал из Seq
. Я хотел бы сохранить его, пока не буду готов, но я также хотел бы получить его размер в O (1). Мне было интересно, есть ли встроенный способ настройки, который позволил бы мне сохранить размер итератора на истребимом объекте.Scala Iterator/Stream с известным размером
ответ
Ваш лучший выбор - обернуть его в другой итератор, если вы можете оплатить стоимость дополнительной косвенности.
class SizedIterator[A](underlying: Iterator[A], val initalSize: Int) extends Iterator[A] {
def next = underlying.next
def hasNext = underlying.hasNext
}
, а затем
new SizedIterator(mySeq.iterator, mySeq.length)
Имейте в виду, однако, что если вы карту или что-то ваш новый SizedIterator
вы будете в конечном итоге с простым Iterator
и уже не знаю, как долго initialSize
было.
Также имейте в виду, что вы не знаете, сколько итератора потребляется, поэтому initialSize
является верхней границей размера, но когда вы его используете, может не быть ни одного.
В качестве альтернативы, вы можете
mySeq.iterator.zipWithIndex.map{ case (x,i) => (x, mySeq.length-1) }.take(mySeq.length)
производить Iterator
, которое пары элемента и число элементов, оставшихся (в том числе, что один - вы будете никогда не ударил нулевой таким образом).
Если вы просто хотите что-то с известным размером, который расскажет вам в O(1)
, в .length
метод на Seq
приведение к Iterable
рассосется так быстро, как метод будет иметь, когда он был Seq
--this весь смысл от переопределяющих методов - и поэтому не будет (обычно) потреблять новый Iterator
каждый раз. Но это требует от вас держать Iterable
, а не только Iterator
.
@ alex23 - Все, что вы делаете с итератором, может потреблять все это (кроме 'hasNext', а' next' будет потреблять только один элемент). Вы можете найти размер, но тогда ничего не осталось (в общем - он даже не обещает этого, но он не обещает, что не будет его потреблять, и это самый простой способ реализовать размер). Ваша единственная надежда состоит в том, чтобы вызывать методы, которые сами возвращают итератор, который вам нужен (который может быть только тем же самым итератором с обновленным состоянием, но это зависит от реализации) до самого последнего вызова (который производит что угодно, если вы закончите с тем, что хотите). –
Я не уверен, что ваш 'SizedIterator' добавляет что-то много над простой парой' (Iterator [T], Int) '... можете ли вы уговорить меня иначе? –
@MilesSabin - Он не предлагает многого. Он поддерживает интерфейс «Итератор [T]», поэтому вы можете передать его в любом месте, где требуется «Итератор [T]», и шаблон снова вернется к нему, чтобы восстановить длину, но обычно это не рекомендуется при попытке написать надежный код. Я предложил его как самое близкое решение того, что требуется. Я не уверен, что было бы лучше попросить что-то еще! –
Зачем вам нужно передавать итератор вместо исходного 'Seq'? Кстати, вы написали * cast * ... Вы не можете отбрасывать из 'Seq' в' Iterator', поэтому я предполагаю, что вы имеете в виду 'seq.iterator'. Мне кажется, что манипулирование итератором, но нужно знать размер, является рискованным. Как только метод, имеющий доступ к итератору, вызывает 'next()', который изменит размер итератора ... – huynhjl
Я мог видеть, что это полезно, если вы производите загрузку данных и намерены бросить их в «Массив». Обычный путь 'Iterator'->' Array' должен использовать массивные массивы, которые являются точными асимптотически, но могут генерировать приличное количество мусора, если у вас много данных, и прискорбно, если вы заранее знаете размер. –