Клуб API Карт

Ошибка в итераторе

upc45
14 мая 2014, 11:34

Добрый день!

 

Есть коллекция меток. При изменении границ видимой области проверяю на выход меток за границы области и если они выходят, то удаляю метки с карты. Код следующий:

    var b = map.getBounds();

    var iterator = gCollection.getIterator(), object, position;

    while ((object = iterator.getNext()) != iterator.STOP_ITERATION) {

        position = object.geometry.getCoordinates();

        if ((position[0] > b[1][0]) || (position[0] < b[0][0]) || (position[1] < b[0][1]) || (position[1] > b[1][1]) ) {

            gCollection.remove(object);

        }

    }

В версии 2.1 итератор работает не верно, а именно если произошло удаление из коллекции, то при подходе к концу итератор не выдает конец коллекции  iterator.STOP_ITERATION, а выдает пустой объект. Таким образом, получаем и не конец коллекции и не объект из коллекции.

В версии 2.0 когда не было  iterator.STOP_ITERATION проверка была на возвращаемый обхект итератором и если он был пустой, то считался конец коллекции. 

Получается, что итератор по коллекции работает без учета изменений в коллекции, т.е. не переходит к следующему элементу (как того требует определение итератора), а выбирает объект из коллекции по следующему индексу, а коллекция уже сместилась на один удаленный элемент ближе к началу.

Есть ли решение?

5 комментариев
Подписаться на комментарии к посту

Такое поведение итератора было скопировано с реализации в FF. Т.е. там также при удалении элементов из массива во время итерирования вы получите неопределенные элементы в конце. Также элементы при удалении могут пропускаться. В описании итераторов в ES6 есть проверка на длину массива, и мы ее добавим, но это не решает проблему пропуска элементов.

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

Это будет уже половина решения (добавление проверки на длину), т.к. сейчас код падает по обращению к null, хотя итератор не вернул конец коллекции.

Я бы назвал ваше предложение как обходной путь проблемы реализации, но никак не обоснование "правильнее было бы...". Предлагаю все-таки вам проанализировать правильность работы и понимания самой сути итератора, а то получается от него никагого плюса (и отличия) по сравнению с индексацией например.

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

В 2.1 коллекция реализована на основе массива. В 2.0 было 2 реализации: на массиве и на двусвязном списке, но список работает значительно медленее и поэтому мы от такой реализации в 2.1. отказались.

не надо в итераторе удалять элементы, это верно для любых коллекций в любом языке программирования, например для Питона:

 

It is not safe to modify the sequence being iterated over in the loop

Спорить не буду, но вводить понятие итератора только для чтения немного смущает.