web-dev-qa-db-fra.com

Quel est le meilleur moyen d'obtenir le nombre / la longueur / la taille d'un itérateur?

Existe-t-il un moyen rapide "de calcul" pour obtenir le nombre d'un itérateur?

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

... semble être une perte de cycles de la CPU.

85
Zak

Si vous venez juste d'avoir l'itérateur, c'est ce que vous devrez faire - ce n'est pas savoir combien d'éléments il reste à parcourir, vous ne pouvez donc pas l'interroger pour obtenir ce résultat . Il y a des méthodes utilitaires qui semblent le faire (comme Iterators.size() en goyave), mais en dessous, elles effectuent à peu près la même opération.

Cependant, de nombreux itérateurs proviennent de collections que vous pouvez souvent interroger pour connaître leur taille. Et s'il s'agit d'une classe utilisateur pour laquelle vous obtenez l'itérateur, vous pouvez envisager de fournir une méthode size () sur cette classe.

En bref, dans la situation où vous seulement avez l'itérateur, alors il n'y a pas de meilleur moyen, mais vous avez beaucoup plus souvent qu'autrefois accès à la collection ou à l'objet sous-jacent dont vous pourrez peut-être obtenir la taille directement.

61
Michael Berry

Utilisation de librairie Guava :

int size = Iterators.size(iterator);

En interne, il se contente de parcourir tous les éléments pour que ce soit plus pratique.

87
Andrejs

Votre code vous donnera une exception lorsque vous atteignez la fin de l'itérateur. Vous pourriez faire:

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

Si vous avez accès à la collection sous-jacente, vous pourrez appeler coll.size()...

EDIT OK vous avez modifié ...

10
assylias

Vous devrez toujours itérer. Pourtant, vous pouvez utiliser Java 8, 9 pour effectuer le comptage sans effectuer de boucle explicite:

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

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

Cela imprime:

5

Il est assez intéressant que vous puissiez paralléliser l'opération de comptage ici en modifiant l'indicateur parallel sur cet appel:

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

En utilisant bibliothèque Guava , une autre option consiste à convertir le Iterable en un List.

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

Utilisez ceci si vous devez également accéder aux éléments de l'itérateur après avoir obtenu sa taille. En utilisant Iterators.size(), vous ne pouvez plus accéder aux éléments itérés.

6
tashuhka

Si tout ce que vous avez est l'itérateur, alors non, il n'y a pas de "meilleure" façon. Si l'itérateur provient d'une collection, vous pouvez le faire pour la taille.

Gardez à l'esprit qu'Iterator n'est qu'une interface permettant de parcourir des valeurs distinctes, vous auriez très bien un code tel que celui-ci.

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

ou

    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");
        }
    }; 
6
Roger Lindsjö

Il n'y a pas de moyen plus efficace, si tout ce que vous avez est l'itérateur. Et si l'itérateur ne peut être utilisé qu'une seule fois, alors obtenir le décompte avant d'obtenir le contenu de l'itérateur est… problématique.

La solution consiste soit à modifier votre application afin qu'elle ne nécessite pas de décompte, soit à obtenir le décompte par un autre moyen. (Par exemple, passez un Collection plutôt que Iterator ...)

4
Stephen C