What is the best way to get the count/length/size of an iterator?

JavaIterator

Java Problem Overview


Is there a "computationally" quick way to get the count of an iterator?

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

... seems like a waste of CPU cycles.

Java Solutions


Solution 1 - Java

Using Guava library:

int size = Iterators.size(iterator);

Internally it just iterates over all elements so its just for convenience.

Solution 2 - Java

If you've just got the iterator then that's what you'll have to do - it doesn't know how many items it's got left to iterate over, so you can't query it for that result. There are utility methods that will seem to do this efficiently (such as Iterators.size() in Guava), but underneath they're just consuming the iterator and counting as they go, the same as in your example.

However, many iterators come from collections, which you can often query for their size. And if it's a user made class you're getting the iterator for, you could look to provide a size() method on that class.

In short, in the situation where you only have the iterator then there's no better way, but much more often than not you have access to the underlying collection or object from which you may be able to get the size directly.

Solution 3 - Java

Your code will give you an exception when you reach the end of the iterator. You could do:

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

If you had access to the underlying collection, you would be able to call coll.size()...

EDIT OK you have amended...

Solution 4 - Java

You will always have to iterate. Yet you can use Java 8, 9 to do the counting without looping explicitely:

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

Here is a test:

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);
}

This prints:

5

Interesting enough you can parallelize the count operation here by changing the parallel flag on this call:

long count = StreamSupport.stream(newIterable.spliterator(), *true*).count();

Solution 5 - Java

Using Guava library, another option is to convert the Iterable to a List.

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

Use this if you need also to access the elements of the iterator after getting its size. By using Iterators.size() you no longer can access the iterated elements.

Solution 6 - Java

If all you have is the iterator, then no, there is no "better" way. If the iterator comes from a collection you could as that for size.

Keep in mind that Iterator is just an interface for traversing distinct values, you would very well have code such as this

	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");
		}
	};

or

	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");
		}
	}; 

Solution 7 - Java

There is no more efficient way, if all you have is the iterator. And if the iterator can only be used once, then getting the count before you get the iterator's contents is ... problematic.

The solution is either to change your application so that it doesn't need the count, or to obtain the count by some other means. (For example, pass a Collection rather than Iterator ...)

Solution 8 - Java

for Java 8 you could use,

public static int getIteratorSize(Iterator iterator){
        AtomicInteger count = new AtomicInteger(0);
        iterator.forEachRemaining(element -> {
            count.incrementAndGet();
        });
        return count.get();
    }

Solution 9 - Java

iterator object contains the same number of elements what your collection contained.

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

But instead of getting the size of iterator and iterating through index 0 to that size, it is better to iterate through the method next() of the iterator.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionZakView Question on Stackoverflow
Solution 1 - JavaAndrejsView Answer on Stackoverflow
Solution 2 - JavaMichael BerryView Answer on Stackoverflow
Solution 3 - JavaassyliasView Answer on Stackoverflow
Solution 4 - Javagil.fernandesView Answer on Stackoverflow
Solution 5 - JavatashuhkaView Answer on Stackoverflow
Solution 6 - JavaRoger LindsjöView Answer on Stackoverflow
Solution 7 - JavaStephen CView Answer on Stackoverflow
Solution 8 - Javarobbie70View Answer on Stackoverflow
Solution 9 - JavaChandra SekharView Answer on Stackoverflow