Existe-t-il un moyen court et simple de générer un List<Integer>
, ou peut-être un Integer[]
ou int[]
, avec des valeurs séquentielles d'une start
valeur à une end
valeur?
C'est-à-dire quelque chose de plus court que, mais équivalent à 1, ce qui suit:
void List<Integer> makeSequence(int begin, int end) {
List<Integer> ret = new ArrayList<>(end - begin + 1);
for (int i=begin; i<=end; i++) {
ret.add(i);
}
return ret;
}
L'utilisation de la goyave est très bien.
Mettre à jour:
Analyse de performance
Étant donné que cette question a reçu plusieurs bonnes réponses, à la fois en utilisant Java 8 natif et des bibliothèques tierces, j'ai pensé tester les performances de toutes les solutions.
Le premier test teste simplement la création d'une liste de 10 éléments en [1..10]
utilisant les méthodes suivantes:
- classicArrayList : le code donné ci-dessus dans ma question (et essentiellement le même que la réponse d'adarshr).
- eclipseCollections : le code donné dans la réponse de Donald ci-dessous en utilisant Eclipse Collections 8.0.
- guavaRange : le code donné dans la réponse de daveb ci-dessous. Techniquement, cela ne crée pas un
List<Integer>
mais plutôt unContiguousSet<Integer>
- mais comme il implémenteIterable<Integer>
dans l'ordre, cela fonctionne principalement pour mes besoins. - intStreamRange : le code donné dans la réponse de Vladimir ci-dessous, qui utilise
IntStream.rangeClosed()
- qui a été introduit dans Java 8. - streamIterate : le code donné dans la réponse de Catalin ci-dessous qui utilise également des
IntStream
fonctionnalités introduites dans Java 8.
Voici les résultats en kilo-opérations par seconde (les nombres plus élevés sont meilleurs), pour tout ce qui précède avec des listes de taille 10:
... et encore pour les listes de taille 10 000:
Ce dernier graphique est correct - les solutions autres que Eclipse et Guava sont trop lentes pour même obtenir une seule barre de pixels! Les solutions rapides sont 10 000 à 20 000 fois plus rapides que les autres.
Ce qui se passe ici, bien sûr, c'est que les solutions de goyave et d'éclipse ne matérialisent en fait aucune sorte de liste de 10000 éléments - ce sont simplement des enveloppes de taille fixe autour des points de départ et d'arrivée. Chaque élément est créé selon les besoins lors de l'itération. Puisque nous n'itérons pas réellement dans ce test, le coût est différé. Toutes les autres solutions matérialisent en fait la liste complète en mémoire et paient un lourd tribut dans un benchmark de création uniquement.
Faisons quelque chose d'un peu plus réaliste et itérons également sur tous les nombres entiers, en les additionnant. Donc, dans le cas de la IntStream.rangeClosed
variante, le benchmark ressemble à:
@Benchmark
public int intStreamRange() {
List<Integer> ret = IntStream.rangeClosed(begin, end).boxed().collect(Collectors.toList());
int total = 0;
for (int i : ret) {
total += i;
}
return total;
}
Ici, les images changent beaucoup, même si les solutions non matérialisantes sont toujours les plus rapides. Voici longueur = 10:
... et longueur = 10 000:
La longue itération sur de nombreux éléments égalise beaucoup les choses, mais l'éclipse et la goyave restent plus de deux fois plus rapides même sur le test de 10000 éléments.
Donc, si vous voulez vraiment une List<Integer>
collection, éclipse semble être le meilleur choix - mais bien sûr, si vous utilisez les flux de manière plus native (par exemple, en oubliant .boxed()
et en réduisant le domaine primitif), vous finirez probablement plus vite que tous ceux-ci. variantes.
1 Peut-être à l'exception de la gestion des erreurs, par exemple, si end
< begin
, ou si la taille dépasse certaines limites d'implémentation ou de JVM (par exemple, des tableaux plus grands que 2^31-1
.