Мне нужно выяснить количество элементов Iterable
в Java. Я знаю, что могу это сделать:
Iterable values = ...
it = values.iterator();
while (it.hasNext()) {
it.next();
sum++;
}
Я также мог бы сделать что-то подобное, потому что мне больше не нужны объекты в Iterable:
it = values.iterator();
while (it.hasNext()) {
it.remove();
sum++;
}
Небольшой тест не показал большой разницы в производительности, никаких комментариев или других идей по этой проблеме?
remove()
не позвонивnext()
заранее.Ответы:
TL; DR: используйте служебный метод
Iterables.size(Iterable)
великой библиотеки Guava .Из ваших двух фрагментов кода вы должны использовать первый, потому что второй удалит все элементы
values
, поэтому впоследствии он будет пустым. Изменение структуры данных для простого запроса, например его размера, является очень неожиданным.Для производительности это зависит от вашей структуры данных. Если это, например, на самом деле
ArrayList
, удаление элементов с самого начала (что делает ваш второй метод) очень медленное (вычисление размера становится O (n * n) вместо O (n), как должно быть).В общем, если есть вероятность, что
values
это действительно a,Collection
а не толькоIterable
, проверьте это и позвонитеsize()
в случае:if (values instanceof Collection<?>) { return ((Collection<?>)values).size(); } // use Iterator here...
Вызов
size()
, как правило, гораздо быстрее , чем подсчет количества элементов, и этот трюк именноIterables.size(Iterable)
из гуавы делает для вас.источник
values
Если вы работаете с java 8, вы можете использовать:
Iterable values = ... long size = values.spliterator().getExactSizeIfKnown();
он будет работать только в том случае, если итеративный источник имеет определенный размер. Большинство Spliterator для коллекций будут, но у вас могут возникнуть проблемы, если они исходят, например, из a
HashSet
илиResultSet
.Вы можете проверить здесь javadoc.
Если Java 8 не подходит или вы не знаете, откуда берется итерация, вы можете использовать тот же подход, что и guava:
if (iterable instanceof Collection) { return ((Collection<?>) iterable).size(); } else { int count = 0; Iterator iterator = iterable.iterator(); while(iterator.hasNext()) { iterator.next(); count++; } return count; }
источник
Возможно, это немного поздно, но может кому-то помочь. Я столкнулся с аналогичной проблемой
Iterable
в моей кодовой базе, и решение было использоватьfor each
без явного вызоваvalues.iterator();
.int size = 0; for(T value : values) { size++; }
источник
Вы можете привести свою итерацию к списку, а затем использовать для нее .size ().
Для ясности, вышеупомянутый метод потребует следующего импорта:
import com.google.common.collect.Lists;
источник
Строго говоря, у Iterable нет размера. Думайте о структуре данных как о цикле.
И подумайте о следующем экземпляре Iterable, без размера:
new Iterable(){ @Override public Iterator iterator() { return new Iterator(){ @Override public boolean hasNext() { return isExternalSystemAvailble(); } @Override public Object next() { return fetchDataFromExternalSystem(); }}; }};
источник
Я бы пошел по
it.next()
простой причине, котораяnext()
гарантированно будет реализована, аremove()
это необязательная операция.источник
remove
уже отмечался как неправильный способ подсчета элементовIterator
, поэтому на самом деле не имеет значения, реализовано то, что мы не собираемся делать, или нет.remove
он реализован, почему было бы неправильно его использовать? Кстати, отрицательные голоса обычно используются для неправильных ответов или ответов, которые дают плохой совет. Я не понимаю, насколько этот ответ подходит для чего-либо из этого.java 8 и выше
StreamSupport.stream(data.spliterator(), false).count();
источник
Как по мне, это просто разные методы. Первый оставляет объект, который вы повторяете, без изменений, а секунды оставляют его пустым. Вопрос в том, что ты хочешь делать. Сложность удаления зависит от реализации вашего итеративного объекта. Если вы используете Коллекции - просто получите размер, подобный предложенному Казекаге Гаара - обычно это лучший подход с точки зрения производительности.
источник
Почему бы вам просто не использовать свой
size()
метод,Collection
чтобы получить количество элементов?Iterator
предназначен только для итерации, ничего больше.источник
Iterator
иIterable
. См. Правильный ответ на голосование.Вместо использования циклов и подсчета каждого элемента или использования сторонней библиотеки мы можем просто указать тип итерации в ArrayList и получить его размер.
источник