173 votes

Comment générer une liste ou un tableau d'entiers séquentiels en Java ?

Existe-t-il un moyen simple et rapide de générer un List<Integer> ou peut-être un Integer[] o int[] avec des valeurs séquentielles de certains start à une valeur end valeur ?

C'est-à-dire quelque chose de plus court, mais d'équivalent à 1 les éléments suivants :

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 une bonne chose.

Mise à jour :

Analyse des performances

Comme cette question a reçu plusieurs bonnes réponses, utilisant à la fois la version native de Java 8 et des bibliothèques tierces, j'ai pensé tester les performances de toutes les solutions.

Le premier test consiste simplement à tester la création d'une liste de 10 éléments [1..10] à l'aide des méthodes suivantes :

  • classicArrayList Le code donné ci-dessus dans ma question (et essentiellement le même que celui de la réponse d'adarshr).
  • eclipseCollections le code donné dans l'article Réponse de Donald ci-dessous en utilisant Eclipse Collections 8.0.
  • guavaRange le code donné dans l'article Réponse de daveb ci-dessous. Techniquement, cela ne crée pas de List<Integer> mais plutôt un ContiguousSet<Integer> - mais comme il met en œuvre Iterable<Integer> dans l'ordre, cela fonctionne en grande partie pour mes besoins.
  • intStreamRange le code donné dans l'article Réponse de Vladimir ci-dessous, qui utilise IntStream.rangeClosed() - qui a été introduite dans Java 8.
  • streamIterate le code donné dans l'article Réponse de Catalin ci-dessous qui utilise également IntStream introduite dans Java 8.

Voici les résultats en kilo-opérations par seconde (les chiffres les plus élevés sont les meilleurs), pour toutes les opérations ci-dessus avec des listes de taille 10 :

List creation throughput

... et à nouveau pour des listes de 10 000 :

enter image description here

Le dernier graphique est exact - les solutions autres qu'Eclipse et Guava sont trop lentes pour obtenir une barre d'un seul pixel ! Les solutions rapides sont de 10 000 à 20 000 fois plus rapide que les autres.

Ce qui se passe ici, bien sûr, c'est que les solutions guava et eclipse ne matérialisent pas réellement une liste de 10 000 éléments - il s'agit simplement d'enveloppes de taille fixe autour des points de départ et d'arrivée. Chaque élément est créé au fur et à mesure des besoins au cours de l'itération. Comme nous n'itérons pas dans ce test, le coût est reporté. Toutes les autres solutions matérialisent en fait la liste complète en mémoire et paient un lourd tribut dans un test de référence portant uniquement sur la création.

Faisons quelque chose d'un peu plus réaliste et itérons également sur tous les entiers, en les additionnant. Ainsi, dans le cas du IntStream.rangeClosed l'indice de référence se présente comme suit :

@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 restent les plus rapides. Voici la longueur = 10 :

List<Integer> Iteration (length=10)

... et longueur = 10 000 :

List<Integer> Iteration (length=10,000)

La longue itération sur un grand nombre d'éléments égalise les choses, mais eclipse et guava restent plus de deux fois plus rapides même sur le test de 10 000 éléments.

Ainsi, si vous vraiment veulent un List<Integer> Les collections eclipse semblent être le meilleur choix - mais bien sûr, si vous utilisez les flux d'une manière plus native (par exemple, en oubliant la fonction .boxed() et en effectuant une réduction dans le domaine primitif), vous serez probablement plus rapide 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 de l'implémentation ou de la JVM (par exemple, les tableaux plus grands que 2^31-1 .

273voto

Vladimir Matveev Points 16593

Avec Java 8, c'est tellement simple qu'il n'y a même plus besoin de méthode distincte :

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

Et en Java 16 ou plus récent :

List<Integer> range = IntStream.rangeClosed(start, end)
    .boxed().toList();

31voto

daveb Points 24831

Eh bien, cette phrase pourrait être qualifiée de "one liner" (utilisation de l'anglais). Gammes de goyaves )

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

Cela ne crée pas de List<Integer> mais ContiguousSet offre à peu près les mêmes fonctionnalités, en particulier la mise en œuvre de Iterable<Integer> qui permet foreach de la même manière que l'application List<Integer> .

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

ImmutableList<Integer> 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]

21voto

Catalin Ciurea Points 1

La version suivante de Java 8 générera [ 1, 2 ,3 ... 10 ]. Le premier arg de iterate est le premier nr de la séquence, et le premier arg de limit est le dernier numéro.

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

10voto

Donald Raab Points 742

Vous pouvez utiliser le Interval de la classe Collections Eclipse .

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

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

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

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

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

Si vous souhaitez éviter de mettre en boîte les entiers en tant qu'entiers, mais que vous souhaitez tout de même obtenir une structure de liste, vous pouvez alors utiliser IntList con IntInterval d'Eclipse Collections.

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

IntList possède les méthodes sum() , min() , minIfEmpty() , max() , maxIfEmpty() , average() y median() disponibles sur l'interface.

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

Un Interval est un List<Integer> mais il est paresseux et immuable. Il est extrêmement utile pour générer des données de test, en particulier si vous utilisez beaucoup de collections. Si vous le souhaitez, vous pouvez facilement copier un intervalle dans un fichier List , Set o Bag comme suit :

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

Un IntInterval est un ImmutableIntList qui étend IntList . Il dispose également de 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 les mêmes equals contrat.

Mise à jour pour Collections Eclipse 9.0

Vous pouvez désormais créer des collections primitives à partir de flux primitifs. Il existe des withAll y ofAll selon votre préférence. Si vous êtes curieux, j'explique pourquoi nous avons les deux. aquí . Ces méthodes existent pour les listes Int/Long/Double, les ensembles, les sacs et les piles 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 un committer pour Eclipse Collections.

6voto

adarshr Points 25912

C'est le plus court que j'ai pu obtenir en utilisant Core Java.

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;  
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X