Итератор не обязательно соответствует чему-то с «счетчиком» ...
Оливер Чарльзуорт
Итераторы такие, какие они есть; для перехода к следующему объекту коллекции (это может быть что-нибудь вроде набора, массива и т. д.). Почему им нужно сообщать размер, когда им все равно, для чего они пытаются выполнить итерацию? to provide an implementation-independent method for access, in which the user does not need to know whether the underlying implementation is some form of array or of linked list, and allows the user go through the collection without explicit indexing.penguin.ewu.edu/~trolfe/LinkedSort/Iterator.html
ecle
Ответы:
67
Если у вас только что есть итератор, то это то, что вам нужно сделать - он не знает, сколько элементов осталось для итерации, поэтому вы не можете запросить его для этого результата. Есть служебные методы, которые, похоже, делают это (например, Iterators.size()в Guava), но ниже они просто выполняют примерно ту же операцию.
Однако многие итераторы поступают из коллекций, размер которых часто можно запросить. И если это пользовательский класс, для которого вы получаете итератор, вы можете подумать о предоставлении метода size () для этого класса.
Короче говоря, в ситуации, когда у вас есть только итератор, лучшего способа нет, но гораздо чаще у вас есть доступ к базовой коллекции или объекту, из которого вы можете напрямую получить размер.
Остерегайтесь побочного эффекта Iterators.size(...)(упомянутого в других комментариях ниже и в java-doc): «Возвращает количество элементов, оставшихся в итераторе. Итератор останется исчерпанным: его метод hasNext () вернет false». Это означает, что вы больше не можете использовать итератор после этого. Lists.newArrayList(some_iterator);может помочь.
Это очень элегантно. Просто помните, что вы потребляете свой итератор (т.е. итератор после этого будет пустым)
lolski
1
Это не «вычислительно быстрый» метод, это удобный метод, который имеет нежелательный побочный эффект использования итератора.
Зак
Не могли бы вы объяснить, как это работает? @Andrejs List <Tuple2 <String, Integer >> wordCountsWithGroupByKey = wordsPairRdd.groupByKey () .mapValues (intIterable -> Iterables.size (intIterable)). Collect (); System.out.println ("wordCountsWithGroupByKey:" + wordCountsWithGroupByKey); «Iterables.size (intIterable)?
Адитья Верма,
15
Ваш код выдаст вам исключение, когда вы дойдете до конца итератора. Вы могли сделать:
int i =0;while(iterator.hasNext()){
i++;
iterator.next();}
Если бы у вас был доступ к базовой коллекции, вы могли бы вызвать coll.size()...
Использование библиотеки Guava , другой вариант заключается в преобразовании Iterableк List.
List list =Lists.newArrayList(some_iterator);int count = list.size();
Используйте это, если вам также нужно получить доступ к элементам итератора после получения его размера. Используя, Iterators.size()вы больше не можете получить доступ к повторяющимся элементам.
@LoveToCode Менее эффективен, чем пример по исходному вопросу
Winter
2
Конечно, создание нового объекта со всеми элементами происходит медленнее, чем простая итерация и удаление. IMHO, это решение однострочное, улучшающее читаемость кода. Я часто использую его для коллекций с небольшим количеством элементов (до 1000) или когда скорость не является проблемой.
tashuhka
7
Если все, что у вас есть, - это итератор, то нет, "лучшего" пути нет. Если итератор поступает из коллекции, вы можете использовать размер.
Имейте в виду, что Iterator - это просто интерфейс для просмотра различных значений, у вас очень хорошо будет такой код, как этот
newIterator<Long>(){finalRandom r =newRandom();@Overridepublicboolean hasNext(){returntrue;}@OverridepublicLong next(){return r.nextLong();}@Overridepublicvoid remove(){thrownewIllegalArgumentException("Not implemented");}};
или
newIterator<BigInteger>(){BigInteger next =BigInteger.ZERO;@Overridepublicboolean hasNext(){returntrue;}@OverridepublicBigInteger next(){BigInteger current = next;
next = next.add(BigInteger.ONE);return current;}@Overridepublicvoid remove(){thrownewIllegalArgumentException("Not implemented");}};
Нет более эффективного способа, если все, что у вас есть, - это итератор. И если итератор можно использовать только один раз, то получить счетчик до того, как вы получите содержимое итератора ... проблематично.
Решение состоит в том, чтобы либо изменить ваше приложение, чтобы оно не нуждалось в подсчете, либо получить счет каким-либо другим способом. (Например, передатьCollection а не Iterator...)
to provide an implementation-independent method for access, in which the user does not need to know whether the underlying implementation is some form of array or of linked list, and allows the user go through the collection without explicit indexing.
penguin.ewu.edu/~trolfe/LinkedSort/Iterator.htmlОтветы:
Если у вас только что есть итератор, то это то, что вам нужно сделать - он не знает, сколько элементов осталось для итерации, поэтому вы не можете запросить его для этого результата. Есть служебные методы, которые, похоже, делают это (например,
Iterators.size()
в Guava), но ниже они просто выполняют примерно ту же операцию.Однако многие итераторы поступают из коллекций, размер которых часто можно запросить. И если это пользовательский класс, для которого вы получаете итератор, вы можете подумать о предоставлении метода size () для этого класса.
Короче говоря, в ситуации, когда у вас есть только итератор, лучшего способа нет, но гораздо чаще у вас есть доступ к базовой коллекции или объекту, из которого вы можете напрямую получить размер.
источник
Iterators.size(...)
(упомянутого в других комментариях ниже и в java-doc): «Возвращает количество элементов, оставшихся в итераторе. Итератор останется исчерпанным: его метод hasNext () вернет false». Это означает, что вы больше не можете использовать итератор после этого.Lists.newArrayList(some_iterator);
может помочь.Использование библиотеки Guava :
Внутри он просто перебирает все элементы, так что это просто для удобства.
источник
Ваш код выдаст вам исключение, когда вы дойдете до конца итератора. Вы могли сделать:
Если бы у вас был доступ к базовой коллекции, вы могли бы вызвать
coll.size()
...ИЗМЕНИТЬ ОК, вы изменили ...
источник
Вам всегда придется повторяться. Тем не менее, вы можете использовать Java 8, 9 для подсчета без явного цикла:
Вот тест:
Это печатает:
Интересно, что вы можете распараллелить операцию подсчета здесь, изменив
parallel
флаг этого вызова:источник
Использование библиотеки Guava , другой вариант заключается в преобразовании
Iterable
кList
.Используйте это, если вам также нужно получить доступ к элементам итератора после получения его размера. Используя,
Iterators.size()
вы больше не можете получить доступ к повторяющимся элементам.источник
Если все, что у вас есть, - это итератор, то нет, "лучшего" пути нет. Если итератор поступает из коллекции, вы можете использовать размер.
Имейте в виду, что Iterator - это просто интерфейс для просмотра различных значений, у вас очень хорошо будет такой код, как этот
или
источник
Нет более эффективного способа, если все, что у вас есть, - это итератор. И если итератор можно использовать только один раз, то получить счетчик до того, как вы получите содержимое итератора ... проблематично.
Решение состоит в том, чтобы либо изменить ваше приложение, чтобы оно не нуждалось в подсчете, либо получить счет каким-либо другим способом. (Например, передать
Collection
а неIterator
...)источник
для Java 8 вы можете использовать,
источник
Объект итератора содержит то же количество элементов, что и ваша коллекция.
Но вместо того, чтобы получать размер итератора и перебирать индекс 0 до этого размера, лучше перебирать метод next () итератора.
источник
a
, а толькоi
?