Как скопировать итератор на другой?

Мне нужно перебирать множество значений для каждой итерации цикла for, но только для первой итерации она отлично работает. После этого itr.hasNext() возвращает false.

Iterator<String> itr = getQuestionIterator(File file);

for(Person p : persons)
{
    while(itr.hasNext())
    {
        String question = itr.next();
        ........
        ........
    }
}

Мне это ясно.

Одним из решений может быть вызов метода getQuestionIterator(File file) в цикле for, так что для каждой итерации цикла он становится повторно инициализированным. Но это очень неэффективный подход, поскольку itr независим.

Я пробовал это Iterator<String> temp = itr, но он не работал, так как он содержит только ссылку.

Есть ли способ скопировать итератор в другой или любой другой лучший подход?

Ответы

Ответ 1

An Iterator - это наименьший возможный API для последовательной обработки данных, поэтому он абстрагируется от основного источника данных. Поскольку он может двигаться только вперед (next()) без какой-либо опции для reset или перемотки назад, это односторонний объект, который следует выбросить после использования. И из-за ограниченного API, который он предлагает, невозможно просто "скопировать" его, не зная реализации и/или основного источника данных.

Итак, есть четыре способа решения вашей проблемы:

(1) Перезагрузите новый итератор из основного источника данных

Просто вызовите getQuestionIterator(File file) каждый раз, когда вам нужно перебирать данные (снова).

  • Преимущество: Простота в использовании и простота в использовании. Не требуется кеш.
  • Недостаток: производительность (например, файл должен быть снова прочитан/обработан). Между тем исходный источник данных мог быть изменен.

(2) Объедините весь код обработки в один цикл итерации

Вместо...

while (iterator.hasNext()) { /* first processing step */ }
while (iterator.hasNext()) { /* second processing step */ }
while (iterator.hasNext()) { /* third processing step */ }
...

... объединить все шаги:

while (iterator.hasNext()) {
    String question = iterator.next();
    /* first processing step */
    /* second processing step */
    /* third processing step */
    ...
}
  • Преимущество: требуется только один итератор. Не требуется кеш.
  • Недостаток: Не всегда возможно, например. если этапы обработки имеют зависимости.

(3) Скопируйте все элементы в локальный кеш (Collection)

Итерации по всем элементам один раз и поместите их в локальную коллекцию, которую вы можете использовать для получения произвольного количества итераторов:

// read everything into a local cache
Collection<String> cache = new ArrayList<>();
while (iterator.hasNext()) cache.add(iterator.next());

// now you can get as many iterators from cache as required:
Iterator<String> iter = cache.iterator();
// use iter

iter = cache.iterator(); // once more
// use iter
...
  • Преимущество: просто реализовать, быстро, как только все данные находятся в кеше.
  • Недостаток: требуется дополнительная память для кэша.

(4) Измените свой API-интерфейс источника данных, чтобы его реализация справилась с проблемой

Значение: Измените getQuestionIterator(File file), чтобы вернуть Iterable<String> вместо Iterator<String>. Вы можете получить произвольное количество итераторов из Iterable:

Iterable<String> iterable = getQuestionIterator(File file);
Iterator<String> iter = iterable.iterator();
// use iter

iter = iterable.iterator(); // once more
// use iter
  • Преимущество: базовый источник данных лучше всего знает, как кэшировать ваши данные. Нет необходимости копировать данные, если базовый источник данных уже использует кеш.
  • Недостаток: Не всегда возможно изменить API.

Ответ 2

Это зависит от точного содержимого вашего кода, но почему бы не перевернуть петли? Проведите внешний цикл над файлом, и для каждой итерации перейдите все Person s:

Iterator<String> itr = getQuestionIterator(File file);
while(itr.hasNext()) 
{
    String question = itr.next();
    for(Person p : persons)
    {    
        ........
        ........
    }
}

Ответ 3

Вы можете только повторить итератор один раз.

Если вам нужно "reset", и воссоздание Итератора дорого (например, чтение из файла), вы можете скопировать данные во временную коллекцию (например, ArrayList). Но для этого требуется достаточно памяти, чтобы держать все сразу.

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