2013-05-05 3 views
0

У меня есть Scala Iterator (я могу использовать любой тип данных для своей цели), который я нарисовал из Seq. Я хотел бы сохранить его, пока не буду готов, но я также хотел бы получить его размер в O (1). Мне было интересно, есть ли встроенный способ настройки, который позволил бы мне сохранить размер итератора на истребимом объекте.Scala Iterator/Stream с известным размером

+1

Зачем вам нужно передавать итератор вместо исходного 'Seq'? Кстати, вы написали * cast * ... Вы не можете отбрасывать из 'Seq' в' Iterator', поэтому я предполагаю, что вы имеете в виду 'seq.iterator'. Мне кажется, что манипулирование итератором, но нужно знать размер, является рискованным. Как только метод, имеющий доступ к итератору, вызывает 'next()', который изменит размер итератора ... – huynhjl

+0

Я мог видеть, что это полезно, если вы производите загрузку данных и намерены бросить их в «Массив». Обычный путь 'Iterator'->' Array' должен использовать массивные массивы, которые являются точными асимптотически, но могут генерировать приличное количество мусора, если у вас много данных, и прискорбно, если вы заранее знаете размер. –

ответ

1

Ваш лучший выбор - обернуть его в другой итератор, если вы можете оплатить стоимость дополнительной косвенности.

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.

+0

@ alex23 - Все, что вы делаете с итератором, может потреблять все это (кроме 'hasNext', а' next' будет потреблять только один элемент). Вы можете найти размер, но тогда ничего не осталось (в общем - он даже не обещает этого, но он не обещает, что не будет его потреблять, и это самый простой способ реализовать размер). Ваша единственная надежда состоит в том, чтобы вызывать методы, которые сами возвращают итератор, который вам нужен (который может быть только тем же самым итератором с обновленным состоянием, но это зависит от реализации) до самого последнего вызова (который производит что угодно, если вы закончите с тем, что хотите). –

+0

Я не уверен, что ваш 'SizedIterator' добавляет что-то много над простой парой' (Iterator [T], Int) '... можете ли вы уговорить меня иначе? –

+0

@MilesSabin - Он не предлагает многого. Он поддерживает интерфейс «Итератор [T]», поэтому вы можете передать его в любом месте, где требуется «Итератор [T]», и шаблон снова вернется к нему, чтобы восстановить длину, но обычно это не рекомендуется при попытке написать надежный код. Я предложил его как самое близкое решение того, что требуется. Я не уверен, что было бы лучше попросить что-то еще! –