Existe-t-il un moyen rapide "de calcul" pour obtenir le nombre d'itérateurs?
int i = 0;
for ( ; some_iterator.hasNext() ; ++i ) some_iterator.next();
... semble être un gaspillage de cycles CPU.
Existe-t-il un moyen rapide "de calcul" pour obtenir le nombre d'itérateurs?
int i = 0;
for ( ; some_iterator.hasNext() ; ++i ) some_iterator.next();
... semble être un gaspillage de cycles CPU.
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
Réponses:
Si vous avez juste l'itérateur, c'est ce que vous devrez faire - il ne sait pas combien d'éléments il reste à parcourir, vous ne pouvez donc pas l'interroger pour ce résultat. Il existe des méthodes utilitaires qui semblent faire cela (comme Iterators.size()
dans Guava), 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 leur taille. Et s'il s'agit d'une classe créée par l'utilisateur pour laquelle vous obtenez l'itérateur, vous pouvez chercher à fournir une méthode size () sur cette classe.
En bref, dans la situation où vous n'avez que l'itérateur, il n'y a pas de meilleur moyen, mais le plus souvent, vous avez accès à la collection ou à l'objet sous-jacent à partir duquel vous pourrez peut-être obtenir directement la taille.
Iterators.size(...)
(mentionné dans d'autres commentaires ci-dessous et dans java-doc): "Renvoie le nombre d'éléments restants dans l'itérateur. L'itérateur sera laissé épuisé: sa méthode hasNext () retournera false." Cela signifie que vous ne pouvez plus utiliser l'itérateur par la suite. Lists.newArrayList(some_iterator);
peut aider.
Utilisation de la bibliothèque Guava :
int size = Iterators.size(iterator);
En interne, il itère simplement sur tous les éléments, donc c'est juste pour plus de commodité.
Votre code vous donnera une exception lorsque vous atteindrez la fin de l'itérateur. Vous pourriez faire:
int i = 0;
while(iterator.hasNext()) {
i++;
iterator.next();
}
Si vous aviez accès à la collection sous-jacente, vous pourriez appeler coll.size()
...
EDIT OK vous avez modifié ...
Vous devrez toujours itérer. Pourtant, vous pouvez utiliser Java 8, 9 pour faire le comptage sans boucler explicitement:
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
Assez intéressant, vous pouvez paralléliser l'opération de comptage ici en changeant le parallel
drapeau sur cet appel:
long count = StreamSupport.stream(newIterable.spliterator(), *true*).count();
En utilisant la bibliothèque Goyave , une autre option est de convertir l' Iterable
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.
Si tout ce que vous avez est l'itérateur, alors non, il n'y a pas de «meilleur» moyen. Si l'itérateur provient d'une collection, vous pourriez aussi bien la taille.
Gardez à l'esprit qu'Iterator est juste une interface pour parcourir des valeurs distinctes, vous auriez très bien un code comme 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");
}
};
Il n'y a pas de moyen plus efficace, si vous ne disposez que de 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 pour qu'elle n'ait pas besoin du décompte, soit à obtenir le décompte par d'autres moyens. (Par exemple, passez un Collection
plutôt que Iterator
...)
L'objet iterator contient le même nombre d'éléments que votre collection contenait.
List<E> a =...;
Iterator<E> i = a.iterator();
int size = a.size();//Because iterators size is equal to list a's size.
Mais au lieu d'obtenir la taille de l'itérateur et d'itérer via l'index 0 à cette taille, il est préférable d'itérer via la méthode next () de l'itérateur.
a
, mais seulement i
?