web-dev-qa-db-fra.com

Obtenir la taille d’un Iterable dans Java

Je dois déterminer 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, parce que je n'ai plus besoin des objets dans l'Iterable:

it = values.iterator();
while (it.hasNext()) {
  it.remove();
  sum++;
}

Un repère à petite échelle n'a pas montré beaucoup de différence de performance, aucun commentaire ou autre idée pour ce problème?

73
js84

TL; DR: Utilisez la méthode utilitaire Iterables.size(Iterable) de la grande bibliothèque Guava .

Parmi vos deux extraits de code, vous devez utiliser le premier, car le second supprimera tous les éléments de values, de sorte qu'il sera vide par la suite. Changer une structure de données pour une requête simple comme sa taille est très inattendu.

Pour des performances, cela dépend de votre structure de données. S'il s'agit par exemple d'un ArrayList, supprimer des éléments du 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 values soit réellement un Collection et pas seulement un Iterable, vérifiez ceci et appelez size() dans le 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 que Iterables.size(Iterable) de Guava = fait pour vous.

106
Philipp Wendler

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 l’auront, mais vous pouvez avoir des problèmes s’il s’agit d’un exemple HashSetou ResultSet.

Vous pouvez vérifier 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 utilisez 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;
    }
34
ArnaudR

C'est peut-être un peu tard, mais peut aider quelqu'un. Je rencontre un problème similaire avec Iterable dans ma base de code et la solution consistait à utiliser for each Sans appeler explicitement values.iterator();.

int size = 0;
for(T value : values) {
   size++;
}
14
pilot

Strictement parlant, Iterable n'a pas de taille. Pensez structure de données comme un cycle.

Et pensez à suivre l'instance Iterable, No size:

    new Iterable(){

        @Override public Iterator iterator() {
            return new Iterator(){

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

                @Override
                public Object next() {
                    return fetchDataFromExternalSystem();
                }};
        }};
6

Vous pouvez convertir votre liste en une liste puis utilisez .size () dessus.

Lists.newArrayList(iterable).size();

Par souci de clarté, la méthode ci-dessus nécessitera l'importation suivante:

import com.google.common.collect.Lists;
5
snacks

Je choisirais it.next() pour la simple raison que next() est implémenté, alors que remove() est une opération facultative.

E next()

Retourne le prochain élément de l'itération.

void remove()

Supprime de la collection sous-jacente le dernier élément renvoyé par l'itérateur (opération facultative).

2
aioobe

Quant à moi, ce ne sont que des méthodes différentes. Le premier laisse l'objet sur lequel vous itérerez inchangé, tandis que les secondes le laissent vide. La question est ce que vous voulez faire. La complexité de la suppression dépend de la mise en œuvre de votre objet itérable. Si vous utilisez Collections - obtenez simplement la taille telle que celle proposée par Kazekage Gaara - il s’agit généralement de la meilleure approche en termes de performances.

0
Mark Bramnik