Comment puis-je générer une liste ou un tableau d’entiers séquentiels en Java?

Existe-t-il une manière simple et courte de générer une List , ou peut-être un Integer[] ou un int[] , avec des valeurs séquentielles allant d’une valeur initiale à une valeur end ?

C’est-à-dire quelque chose de plus court que, mais équivalent à 1 :

 void List makeSequence(int begin, int end) { List ret = new ArrayList(end - begin + 1); for (int i=begin; i<=end; i++) { ret.add(i); } return ret; } 

L’utilisation de goyave est bien.

Mettre à jour:

Analyse de performance

Étant donné que cette question a reçu plusieurs bonnes réponses, à la fois en utilisant des bibliothèques Java 8 natives 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 [1..10] utilisant les méthodes suivantes:

  • classicArrayList : le code donné ci-dessus dans ma question (et essentiellement la même que la réponse d’adarshr).
  • eclipseCollections : le code donné dans la réponse de Donald ci-dessous à l’aide d’Eclipse Collections 8.0.
  • guavaRange : le code donné dans la réponse de daveb ci-dessous. Techniquement, cela ne crée pas un List mais un ContiguousSet – mais comme il implémente Iterable 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 la fonctionnalité IntStream introduite dans Java 8.

Voici les résultats en kilo-opérations par seconde (les nombres les plus élevés sont meilleurs), pour tout ce qui précède avec des listes de taille 10:

Débit de création de liste

… et encore pour les listes de taille 10 000:

entrer la description de l'image ici

Ce dernier graphique est correct – les solutions autres que Eclipse et Guava sont trop lentes pour 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 réalité aucune liste de 10 000 éléments – ce sont simplement des encapsuleurs 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. Comme 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 sortingbut dans un benchmark de création.

Faisons quelque chose de plus réaliste et parcourons tous les nombres entiers en les additionnant. Donc, dans le cas de la variante IntStream.rangeClosed , le IntStream.rangeClosed ressemble à IntStream.rangeClosed :

 @Benchmark public int intStreamRange() { List ret = IntStream.rangeClosed(begin, end).boxed().collect(Collectors.toList()); int total = 0; for (int i : ret) { total += i; } return total; } 

Ici, les images changent énormément, même si les solutions non matérialisantes sont toujours les plus rapides. Voici la longueur = 10:

<img src="http://soffr.miximages.com/collections/VQDYA.png" alt="Liste Itération (longueur = 10)”>

… et longueur = 10.000:

<img src="http://soffr.miximages.com/collections/LWWtu.png" alt="Liste Itération (longueur = 10 000)”>

La longue itération de nombreux éléments améliore considérablement les choses, mais l’éclipse et la goyave restnt plus de deux fois plus rapides, même sur le test de 10 000 éléments.

Donc, si vous voulez vraiment un List , les collections eclipse semblent être le meilleur choix – mais bien sûr si vous utilisez les stream de manière plus native (par exemple, en oubliant .boxed() et en réduisant le domaine primitif) Je vais probablement finir plus vite que toutes ces 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 baies supérieures à 2^31-1 .

Avec Java 8, c’est si simple qu’il n’a même plus besoin de méthode séparée:

 List range = IntStream.rangeClosed(start, end) .boxed().collect(Collectors.toList()); 

Eh bien, ce seul paquebot pourrait être admissible (utilise des gammes de goyave )

  ContiguousSet integerList = ContiguousSet.create(Range.closedOpen(0, 10), DiscreteDomain.integers()); System.out.println(integerList); 

Cela ne crée pas de List , mais ContiguousSet offre les mêmes fonctionnalités, en particulier en implémentant Integer ce qui permet une implémentation identique à celle de List .

Dans les anciennes versions (quelque part avant Guava 14), vous pouviez utiliser ceci:

  ImmutableList integerList = Ranges.closedOpen(0, 10).asSet(DiscreteDomains.integers()).asList(); System.out.println(integerList); 

Les deux produisent:

 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

C’est le plus court possible avec Core Java.

 List makeSequence(int begin, int end) { List ret = new ArrayList(end - begin + 1); for(int i = begin; i <= end; i++, ret.add(i)); return ret; } 

Vous pouvez utiliser la classe Interval des collections Eclipse .

 List range = Interval.oneTo(10); range.forEach(System.out::print); // prints 12345678910 

La classe Interval est paresseuse et ne stocke donc pas toutes les valeurs.

 LazyIterable range = Interval.oneTo(10); System.out.println(range.makeSsortingng(",")); // prints 1,2,3,4,5,6,7,8,9,10 

Votre méthode pourrait être mise en œuvre comme suit:

 public List makeSequence(int begin, int end) { return Interval.fromTo(begin, end); } 

Si vous souhaitez éviter la boxe inte en tant qu’Integers, mais que vous souhaitez toujours une structure de liste, vous pouvez utiliser IntList avec IntInterval des collections Eclipse.

 public IntList makeSequence(int begin, int end) { return IntInterval.fromTo(begin, end); } 

IntList a les méthodes sum() , min() , minIfEmpty() , max() , maxIfEmpty() , average() et median() disponibles sur l’interface.

Mise à jour pour plus de clarté: 27/11/2017

Un Interval est une List , mais il est paresseux et immuable. Il est extrêmement utile pour générer des données de test, surtout si vous traitez beaucoup avec les collections. Si vous le souhaitez, vous pouvez facilement copier un intervalle dans une List , un Set ou un Bag comme suit:

 Interval integers = Interval.oneTo(10); Set set = integers.toSet(); List list = integers.toList(); Bag bag = integers.toBag(); 

Un IntInterval est un ImmutableIntList qui étend IntList . Il a également des méthodes de conversion.

 IntInterval ints = IntInterval.oneTo(10); IntSet set = ints.toSet(); IntList list = ints.toList(); IntBag bag = ints.toBag(); 

Un Interval et un IntInterval n’ont pas le même contrat d’ equals .

Mise à jour pour les collections Eclipse 9.0

Vous pouvez maintenant créer des collections primitives à partir de stream primitifs. Il y a withAll et ofAll selon vos préférences. Si vous êtes curieux, j’explique pourquoi nous avons les deux ici . Ces méthodes existent pour les listes int / long / double, ensembles, sacs et stacks mutables et immuables.

 Assert.assertEquals( IntInterval.oneTo(10), IntLists.mutable.withAll(IntStream.rangeClosed(1, 10))); Assert.assertEquals( IntInterval.oneTo(10), IntLists.immutable.withAll(IntStream.rangeClosed(1, 10))); 

Note: je suis committer pour les collections Eclipse

La version Java à 1 ligne suivante génèrera [1, 2, 3 … 10]. Le premier argument de iterate est le premier nr de la séquence et le premier argument de la limit est le dernier nombre.

 List numbers = Stream.iterate(1, n -> n + 1) .limit(10) .collect(Collectors.toList()); 

Vous pourriez utiliser les gammes de goyave

Vous pouvez obtenir un SortedSet en utilisant

 ImmutableSortedSet set = Ranges.open(1, 5).asSet(DiscreteDomains.integers()); // set contains [2, 3, 4] 

C’est le plus court que j’ai pu trouver.

Version de liste

 public List makeSequence(int begin, int end) { List ret = new ArrayList(++end - begin); for (; begin < end; ) ret.add(begin++); return ret; } 

Version tableau

 public int[] makeSequence(int begin, int end) { if(end < begin) return null; int[] ret = new int[++end - begin]; for (int i=0; begin < end; ) ret[i++] = begin++; return ret; } 

Celui-ci pourrait fonctionner pour vous ….

 void List makeSequence(int begin, int end) { AtomicInteger ai=new AtomicInteger(begin); List ret = new ArrayList(end-begin+1); while ( end-->begin) { ret.add(ai.getAndIncrement()); } return ret; }