Как получить индекс текущего цикла при использовании Iterator?

108

Я использую Iterator для перебора коллекции и хочу получить индекс текущего элемента.

Как я могу это сделать?

Махмуд Салех
источник
1
@finnw Не думаю, что они дублируются. Этот вопрос задается с использованием Iterator, другой - для каждого цикла. Оба вопроса решаются схожим подходом, поэтому ответы дублируются, а не вопрос.
Роберт

Ответы:

92

Используйте свою собственную переменную и увеличивайте ее в цикле.

Крис Дайвер
источник
6
Но также см. Предложение @ mateusz-dymczyk о it.nextIndex(). Полезно, когда коллекция представляет собой список.
noamtm 06
114

У меня был тот же вопрос, и я обнаружил, что сработал ListIterator. Аналогично тесту выше:

List<String> list = Arrays.asList("zero", "one", "two");

ListIterator iter = list.listIterator();

while (iter.hasNext()) {
    System.out.println("index: " + iter.nextIndex() + " value: " + iter.next());
}

Убедитесь, что вы вызываете nextIndex ДО того, как действительно получите next ().

Павел
источник
5
Спасибо за упоминание: «Убедитесь, что вы вызываете следующий индекс ДО того, как вы действительно получите следующий ()»
Гангадхар ДЖАННУ,
Спасибо, я не знал об этом раньше. Я хотел бы сделать предостережение: ListIterator двунаправлен, а Iterator - однонаправлен. Пока вы избегаете перемещаться вперед и назад с помощью курсора, вы должны быть в безопасности.
user2910265
28

Вот способ сделать это, используя вашу собственную переменную и сохраняя ее краткость:

List<String> list = Arrays.asList("zero", "one", "two");

int i = 0;
for (Iterator<String> it = list.iterator(); it.hasNext(); i++) {
    String s = it.next();
    System.out.println(i + ": " + s);
}

Вывод (как вы уже догадались):

0: zero
1: one
2: two

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

Том Клифт
источник
3
Если вы создаете итератор самостоятельно, вы также можете использовать ListIterator и не нуждаетесь в отдельной переменной int.
Роберт Клемме
1
Если вы используете «статический импорт» для Arrays.asList, тогда вы можете просто написатьasList("zero", "one", "two")
karmakaze
Именно так я поступил до того, как прочитал ответ Пола. Я бы сильно отговорил ваш путь, потому что не вижу в этом никакой пользы. Как вы думаете, есть преимущество (кроме упомянутого). Почему вы не использовали цикл для каждого? Явное определение Итератора не требуется, если вы используете свою собственную переменную.
Вилли Ментцель
@progressive_overload, если вам нужен итератор (в соответствии с вопросом, например, для перехода в библиотеку), который в примере не показан. В этом примере у вас есть переменная вне цикла, и вам нужно быть осторожным, чтобы вызвать #next один раз. В примере Пола нет переменных вне цикла, но вам нужно быть осторожным, чтобы вызвать #next и #nextIndex вместе один раз (и на практике, если они используются более одного раза, они будут помещены в локальные переменные, чего в этом примере нет. т показать).
Том Клифт
23

Для ListIteratorподсчета можно использовать :

final List<String> list = Arrays.asList("zero", "one", "two", "three");

for (final ListIterator<String> it = list.listIterator(); it.hasNext();) {
    final String s = it.next();
    System.out.println(it.previousIndex() + ": " + s);
}
Роберт Клемме
источник
12

Что за коллекция? Если это реализация интерфейса List, вы можете просто использовать it.nextIndex() - 1.

Матеуш Дымчик
источник
4

Используйте ListIterator для итерации по коллекции. Если Коллекция не является списком, с которого можно начать, сначала Arrays.asList(Collection.toArray())нужно превратить ее в список.

Jatin
источник
3

просто сделайте что-нибудь вроде этого:

        ListIterator<String> it = list1.listIterator();
        int index = -1;
        while (it.hasNext()) {
            index++;
            String value = it.next();
            //At this point the index can be checked for the current element.

        }
Солнечно
источник
4
Вызов indexOf () потребует дополнительного сканирования списка устройств. Будет быстрее просто увеличить локальный счетчик.
Грег Браун
1
согласовано. это не самое эффективное решение.
Sunny
1
Похоже, вы обновили пример, чтобы сделать его более эффективным.
Грег Браун
2

Используйте int и увеличивайте его в своем цикле.

Флориан Райшль
источник
1

Смотрите здесь .

iterator.nextIndex()предоставит индекс элемента, который будет возвращен при последующем вызове next().

Веселый
источник
Интерфейс Iterator НЕ имеет метода nextIndex (). Для этого вам нужно явно использовать ListIterator, но OP задал вопрос конкретно об Iterator.
Fran Marzoa
0

Все, что вам нужно, это использовать iterator.nextIndex (), чтобы вернуть текущий индекс, на котором находится итератор. Это может быть немного проще, чем использование вашей собственной переменной счетчика (которая также работает).

public static void main(String[] args) {    
    String[] str1 = {"list item 1", "list item 2", "list item 3", "list item 4"};
    List<String> list1 = new ArrayList<String>(Arrays.asList(str1));

    ListIterator<String> it = list1.listIterator();

    int x = 0;

    //The iterator.nextIndex() will return the index for you.
    while(it.hasNext()){
        int i = it.nextIndex();
        System.out.println(it.next() + " is at index" + i); 
    }
}

Этот код будет просматривать список list1 по одному элементу за раз и печатать текст элемента, затем «находится в индексе», после чего он будет печатать индекс, по которому итератор нашел его. :)

Райан
источник
1
На самом деле ваш код отключен на единицу, потому что он пытается отобразить индекс ПОСЛЕ вызова it.next ().
Хенрик Остед Соренсен
0

Хотя у вас уже был ответ, подумал добавить некоторую информацию.

Как вы явно упомянули Коллекции, вы не можете использовать listIterator для получения индекса для всех типов коллекций.

Список интерфейсов - ArrayList, LinkedList, Vector и Stack.

Имеет оба iterator()иlistIterator()

Установить интерфейсы - HashSet, LinkedHashSet, TreeSet и EnumSet.

Есть только iterator()

Интерфейсы карты - HashMap, LinkedHashMap, TreeMap и IdentityHashMap

Не имеет итераторов, но может повторяться с помощью keySet()/ values()или entrySet()as keySet()и entrySet()возвращает Setи values()возвращаетCollection .

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

Виньеш Раджа
источник
-1

Это было бы самым простым решением!

std::vector<double> v (5);

for(auto itr = v.begin();itr != v.end();++itr){

 auto current_loop_index = itr - v.begin();

  std::cout << current_loop_index << std::endl;

}

Проверено на gcc-9 с -std=c++11флагом

Вывод:

0
1
2
3
4

Приятель
источник