web-dev-qa-db-fra.com

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

Existe-t-il un moyen simple et agréable de générer un List<Integer>, Ou peut-être un Integer[] Ou int[], Avec des valeurs séquentielles allant de la valeur start à un end valeur?

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

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 goyave est bien.

Mise à jour:

Analyse de performance

Puisque cette question a reçu plusieurs bonnes réponses, à la fois en utilisant des bibliothèques natives Java 8 et tierces), je pensais tester les performances de toutes les solutions.

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

  • classicArrayList : code indiqué ci-dessus dans ma question (et essentiellement identique à la réponse d'adarshr).
  • eclipseCollections : code indiqué entre réponse de Donald ci-dessous, à l'aide de Eclipse Collections 8.0.
  • guavaRange : code indiqué dans réponse de daveb ci-dessous. Techniquement, cela ne crée pas un List<Integer> Mais plutôt un ContiguousSet<Integer> - mais comme il implémente Iterable<Integer> Dans l'ordre, cela fonctionne principalement pour mes besoins.
  • intStreamRange : le code donné en réponse de Vladimir ci-dessous, qui utilise IntStream.rangeClosed() - qui a été introduit dans = Java 8.
  • streamIterate : code indiqué dans 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 (plus les nombres sont élevés, mieux c'est), pour tout ce qui précède avec des listes de taille 10:

List creation throughput

... et encore pour les listes de taille 10 000:

enter image description here

Ce dernier graphique est correct: les solutions autres que Eclipse et Guava sont trop lentes pour obtenir une barre de pixel! Les solutions rapides vont de 10 000 à 20 000 fois plus rapidement que les autres.

Bien entendu, les solutions Gava et Eclipse ne matérialisent aucune liste de 10 000 éléments - elles sont simplement des enveloppeurs de taille fixe entourant les points de départ et les points de terminaison. Chaque élément est créé selon les besoins lors de l'itération. Puisque nous n'effectuons pas réellement cette itération 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 seulement.

Faisons quelque chose d'un peu plus réaliste et parcourons également tous les entiers en les additionnant. Ainsi, dans le cas de la variante IntStream.rangeClosed, Le repère 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, bien que les solutions non matérialisantes restent les plus rapides. Voici longueur = 10:

List<Integer> Iteration (length=10)

... et longueur = 10 000:

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

La longue itération sur de nombreux éléments apporte beaucoup d'équilibre, mais Eclipse et la goyave restent deux fois plus rapides, même sur le test des 10 000 éléments.

Donc si vous vraiment voulez un List<Integer>, Les collections Eclipse semblent être le meilleur choix - mais bien sûr, si vous utilisez des flux de manière plus native (par exemple, en oubliant .boxed() et en réduisant le domaine primitif) vous finirez probablement plus vite que toutes ces variantes.


1 Peut-être à l'exception du traitement des erreurs, par exemple, si end <begin, ou si la taille dépasse certaines limites d'implémentation ou JVM (par exemple, des tableaux plus grands que 2^31-1.

95
BeeOnRope

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

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

Eh bien, cette doublure pourrait être admissible (utilise Chaînes de goyave )

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

Cela ne crée pas un List<Integer>, mais ContiguousSet offre à peu près les mêmes fonctionnalités, en particulier pour implémenter Integer<Integer> qui permet la mise en oeuvre de foreach de la même manière que List<Integer>.

Dans les anciennes versions (quelque part avant Guava 14), vous pourriez 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]
26
daveb

Le one-liner suivant Java 8 générera [1, 2, 3 ... 10]. Le premier argument de iterate est le premier numéro de la séquence et le premier argument de limit est le dernier nombre.

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

C'est le plus court possible avec 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;  
}
6
adarshr

Vous pouvez utiliser la classe Interval de Eclipse Collections .

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

La classe Interval est paresseuse, elle 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 implémentée comme suit:

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

Si vous voulez éviter de faire de la boxe en tant qu'entiers, mais que vous voulez toujours une structure de liste, vous pouvez utiliser IntList avec IntInterval de Eclipse Collections.

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() disponible sur l'interface.

Mise à jour pour plus de clarté: 11/27/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 sur un List, Set ou 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 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 equals.

Mise à jour pour Eclipse Collections 9.

Vous pouvez maintenant créer des collections primitives à partir de flux primitifs. Il existe withAll et ofAll méthodes en fonction de vos préférences. Si vous êtes curieux, j'explique pourquoi nous avons les deux ici . Ces méthodes existent pour les listes, ensembles, sacs et piles In/Long/Double 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)));

Remarque: je suis un partisan des collections Eclipse

5
Donald Raab

Vous pouvez utiliser Guava Ranges

Vous pouvez obtenir un SortedSet en utilisant

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

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

Version de liste

public List<Integer> makeSequence(int begin, int end)
{
    List<Integer> ret = new ArrayList<Integer>(++end - begin);

    for (; begin < end; )
        ret.add(begin++);

    return ret;
}

Version du 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;
}
0
Code Behind