Каков наилучший способ получить количество / длину / размер итератора? - PullRequest
81 голосов
/ 15 марта 2012

Есть ли "вычислительный" быстрый способ получить счетчик итератора?

int i = 0;
for ( ; some_iterator.hasNext() ; ++i ) some_iterator.next();

... кажется пустой тратой циклов ЦП.

Ответы [ 8 ]

85 голосов
/ 11 ноября 2014

Использование Библиотека Guava :

int size = Iterators.size(iterator);

Внутренне он просто перебирает все элементы, так что это просто для удобства.

60 голосов
/ 15 марта 2012

Если вы только что получили итератор, то это то, что вам нужно сделать - он не не знает , сколько осталось элементов для повторения, поэтому вы не можете запросить его дляэтот результат.Существуют служебные методы, которые, кажется, делают это (например, Iterators.size() в Guava), но под ними они просто выполняют примерно ту же операцию.

Однако многие итераторы происходят из коллекций, которые вы часто можетезапросить их размер.И если это пользовательский класс, для которого вы получаете итератор, вы можете использовать метод size () для этого класса.

Короче говоря, в ситуации, когда вы only если у вас есть итератор, то лучшего способа нет, но гораздо чаще вы получаете доступ к базовой коллекции или объекту, из которого вы можете получить размер напрямую.

9 голосов
/ 15 марта 2012

Ваш код выдаст вам исключение, когда вы достигнете конца итератора. Вы могли бы сделать:

int i = 0;
while(iterator.hasNext()) {
    i++;
    iterator.next();
}

Если бы у вас был доступ к базовой коллекции, вы могли бы позвонить coll.size() ...

EDIT ОК, вы изменили ...

6 голосов
/ 11 января 2018

Вам всегда придется повторяться.Тем не менее, вы можете использовать Java 8, 9 для выполнения подсчета без явного цикла:

Iterable<Integer> newIterable = () -> iter;
long count = StreamSupport.stream(newIterable.spliterator(), false).count();

Вот тест:

public static void main(String[] args) throws IOException {
    Iterator<Integer> iter = Arrays.asList(1, 2, 3, 4, 5).iterator();
    Iterable<Integer> newIterable = () -> iter;
    long count = StreamSupport.stream(newIterable.spliterator(), false).count();
    System.out.println(count);
}

Это печатает:

5

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

long count = StreamSupport.stream(newIterable.spliterator(), *true*).count();
6 голосов
/ 06 октября 2015

Используя Библиотека Guava , другой вариант - преобразовать Iterable в List.

List list = Lists.newArrayList(some_iterator);
int count = list.size();

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

6 голосов
/ 15 марта 2012

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

Имейте в виду, что Iterator - это просто интерфейс для обхода различных значений, у вас очень хорошо было бы иметь такой код

    new Iterator<Long>() {
        final Random r = new Random();
        @Override
        public boolean hasNext() {
            return true;
        }

        @Override
        public Long next() {
            return r.nextLong();
        }

        @Override
        public void remove() {
            throw new IllegalArgumentException("Not implemented");
        }
    };

или

    new Iterator<BigInteger>() {
        BigInteger next = BigInteger.ZERO;

        @Override
        public boolean hasNext() {
            return true;
        }

        @Override
        public BigInteger next() {
            BigInteger current = next;
            next = next.add(BigInteger.ONE);
            return current;
        }

        @Override
        public void remove() {
            throw new IllegalArgumentException("Not implemented");
        }
    }; 
4 голосов
/ 15 марта 2012

Нет более эффективного способа, если у вас есть только итератор.И если итератор может использоваться только один раз, то получить счетчик до того, как вы получите содержимое итератора, ... проблематично.

Решение состоит в том, чтобы либо изменить приложение, чтобы ему не требовался счетили получить счет другим способом.(Например, передайте Collection вместо Iterator ...)

0 голосов
/ 15 марта 2012

объект итератора содержит то же количество элементов, что и ваша коллекция.

List<E> a =...;
Iterator<E> i = a.iterator();
int size = a.size();//Because iterators size is equal to list a's size.

Но вместо получения размера итератора и итерации по индексу 0 до этого размера лучше выполнить итерацию по методу next () итератора.

...