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:
É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:
List
mais un ContiguousSet
– mais comme il implémente Iterable
dans l’ordre, cela fonctionne principalement pour mes besoins. IntStream.rangeClosed()
– qui a été introduit dans Java 8. 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:
… 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 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; }