J'ai besoin de comprendre le nombre d'éléments dans un Iterable
en Java. Je sais que je peux le faire:
Iterable values = ...
it = values.iterator();
while (it.hasNext()) {
it.next();
sum++;
}
Je pourrais aussi faire quelque chose comme ça, car je n'ai plus besoin des objets dans Iterable:
it = values.iterator();
while (it.hasNext()) {
it.remove();
sum++;
}
Un benchmark à petite échelle n'a pas montré beaucoup de différence de performance, des commentaires ou d'autres idées pour ce problème?
remove()
sans appelernext()
au préalable.Réponses:
TL; DR: Utilisez la méthode utilitaire
Iterables.size(Iterable)
de la grande bibliothèque Guava .De vos deux extraits de code, vous devez utiliser le premier, car le second supprimera tous les éléments
values
, il sera donc vide par la suite. Changer une structure de données pour une requête simple telle que sa taille est très inattendu.Pour les performances, cela dépend de votre structure de données. Si c'est par exemple en fait un
ArrayList
, supprimer des éléments depuis le début (ce que fait votre deuxième méthode) est très lent (le calcul de la taille devient O (n * n) au lieu de O (n) comme il se doit).En général, s'il y a une chance que ce
values
soit réellement unCollection
et pas seulement unIterable
, vérifiez ceci et appelezsize()
au cas où:if (values instanceof Collection<?>) { return ((Collection<?>)values).size(); } // use Iterator here...
L'appel à
size()
sera généralement beaucoup plus rapide que de compter le nombre d'éléments, et cette astuce est exactement ce queIterables.size(Iterable)
de goyave fait pour vous.la source
values
Si vous travaillez avec java 8, vous pouvez utiliser:
Iterable values = ... long size = values.spliterator().getExactSizeIfKnown();
cela ne fonctionnera que si la source itérable a une taille déterminée. La plupart des Spliterators for Collections le feront, mais vous pouvez avoir des problèmes si cela vient d'un
HashSet
ouResultSet
par exemple.Vous pouvez consulter le javadoc ici.
Si Java 8 n'est pas une option , ou si vous ne savez pas d'où vient l'itérable, vous pouvez utiliser la même approche que la goyave:
if (iterable instanceof Collection) { return ((Collection<?>) iterable).size(); } else { int count = 0; Iterator iterator = iterable.iterator(); while(iterator.hasNext()) { iterator.next(); count++; } return count; }
la source
C'est peut-être un peu tard, mais cela peut aider quelqu'un. Je rencontre un problème similaire
Iterable
dans ma base de code et la solution consistait à utiliserfor each
sans appeler explicitementvalues.iterator();
.int size = 0; for(T value : values) { size++; }
la source
Vous pouvez convertir votre itérable dans une liste, puis utiliser .size () dessus.
Par souci de clarté, la méthode ci-dessus nécessitera l'importation suivante:
import com.google.common.collect.Lists;
la source
À proprement parler, Iterable n'a pas de taille. Pensez à la structure de données comme à un cycle.
Et pensez à suivre l'instance Iterable, aucune taille:
new Iterable(){ @Override public Iterator iterator() { return new Iterator(){ @Override public boolean hasNext() { return isExternalSystemAvailble(); } @Override public Object next() { return fetchDataFromExternalSystem(); }}; }};
la source
J'irais pour
it.next()
la simple raison quinext()
est garantie d'être implémentée, alors queremove()
c'est une opération facultative.la source
remove
a déjà été noté comme une mauvaise façon de compter les éléments d'unIterator
, donc peu importe si la chose que nous n'allons pas faire est implémentée ou non.remove
est mis en œuvre, pourquoi serait-il erroné de l'utiliser? Btw, les votes négatifs ne sont généralement pas utilisés pour de mauvaises réponses ou des réponses qui donnent de mauvais conseils. Je ne vois pas comment cette réponse se qualifie pour tout cela.java 8 et supérieur
StreamSupport.stream(data.spliterator(), false).count();
la source
Quant à moi, ce ne sont que des méthodes différentes. Le premier laisse l'objet sur lequel vous itérez inchangé, tandis que les secondes le laisse vide. La question est de savoir que voulez-vous faire. La complexité de la suppression est basée sur l'implémentation de votre objet itérable. Si vous utilisez des collections - obtenez simplement la taille proposée par Kazekage Gaara - c'est généralement la meilleure approche en termes de performances.
la source
Pourquoi n'utilisez-vous pas simplement la
size()
méthode sur votreCollection
pour obtenir le nombre d'éléments?Iterator
est juste destiné à itérer, rien d'autre.la source
Iterator
etIterable
. Voir la réponse votée pour la bonne manière.Au lieu d'utiliser des boucles et de compter chaque élément ou d'utiliser une bibliothèque tierce, nous pouvons simplement typer l'itérable dans ArrayList et obtenir sa taille.
la source