Comment convertir un ArrayList contenant des entiers en tableau int primitif?

297

J'essaie de convertir une ArrayList contenant des objets Integer en primitive int [] avec le morceau de code suivant, mais cela génère une erreur de temps de compilation. Est-il possible de convertir en Java?

List<Integer> x =  new ArrayList<Integer>();
int[] n = (int[])x.toArray(int[x.size()]);
Snehal
la source
10
Pas une copie EXACTE de cette question (bien que pas très loin non plus)
Jonik
1
Oui, il s'agit d'une ArrayList, "duplicate" concerne un tableau normal.
Scott McIntyre
3
Si vous n'avez pas besoin d'entiers primitifs, vous pouvez utiliser: List<Integer> x = new ArrayList<Integer>(); Integer[] n = x.toArray(new Integer[0]);
Evorlor

Réponses:

219

Vous pouvez convertir, mais je ne pense pas qu'il y ait quelque chose de intégré pour le faire automatiquement:

public static int[] convertIntegers(List<Integer> integers)
{
    int[] ret = new int[integers.size()];
    for (int i=0; i < ret.length; i++)
    {
        ret[i] = integers.get(i).intValue();
    }
    return ret;
}

(Notez que cela lèvera une NullPointerException si l'un integersou l'autre des éléments qu'il contient null.)

EDIT: Selon les commentaires, vous voudrez peut-être utiliser l'itérateur de liste pour éviter des coûts désagréables avec des listes telles que LinkedList:

public static int[] convertIntegers(List<Integer> integers)
{
    int[] ret = new int[integers.size()];
    Iterator<Integer> iterator = integers.iterator();
    for (int i = 0; i < ret.length; i++)
    {
        ret[i] = iterator.next().intValue();
    }
    return ret;
}
Jon Skeet
la source
21
Il peut être préférable d'itérer en utilisant l'itérateur de la liste (avec pour chacun) afin d'éviter les résultats de performance sur les listes dont l'accès n'est pas O (1).
Matthew Willis
@Matthew: Oui, peut-être - modifiera pour donner cela comme alternative.
Jon Skeet du
1
Vous pouvez également utiliser le fait que ArrayList implémente Iterable (via l'héritage Collection) et faire: for (int n: integer) {ret [counter ++] = n; } ... et initialiser int counter = 0;
gardarh
8
beaucoup plus facile maintenant en Java8:integers.stream().mapToInt(Integer::valueOf).toArray
Manish Patel
241

Si vous utilisez il y a aussi une autre façon de procéder.

int[] arr = list.stream().mapToInt(i -> i).toArray();

Ce qu'il fait, c'est:

  • obtenir un Stream<Integer>de la liste
  • obtention d'un IntStreamen mappant chaque élément sur lui-même (fonction d'identité), déballage de la intvaleur détenue par chaque Integerobjet (fait automatiquement depuis Java 5)
  • obtenir le tableau inten appelanttoArray

Vous pouvez également appeler explicitement intValuevia une référence de méthode, c'est-à-dire:

int[] arr = list.stream().mapToInt(Integer::intValue).toArray();

Il convient également de mentionner que vous pouvez en obtenir un NullPointerExceptionsi vous avez une nullréférence dans la liste. Cela pourrait être facilement évité en ajoutant une condition de filtrage au pipeline de flux comme ceci:

                       //.filter(Objects::nonNull) also works
int[] arr = list.stream().filter(i -> i != null).mapToInt(i -> i).toArray();

Exemple:

List<Integer> list = Arrays.asList(1, 2, 3, 4);
int[] arr = list.stream().mapToInt(i -> i).toArray(); //[1, 2, 3, 4]

list.set(1, null); //[1, null, 3, 4]
arr = list.stream().filter(i -> i != null).mapToInt(i -> i).toArray(); //[1, 3, 4]
Alexis C.
la source
Je vois que cela peut être utilisé pour les doubletypes; n'y a-t-il pas d'équivalent pour les floattypes?
code_dredd
J'ai vu les avantages de Java 8 en expliquant en détail.
Eugene
Et c'est pourquoi l'API Java 8+ Stream est magnifique.
Pranav A.
67

Google Guava

Google Guava offre un moyen pratique de le faire en appelant Ints.toArray.

List<Integer> list = ...;
int[] values = Ints.toArray(list);
Snehal
la source
6
Je pense que ce sera la réponse pour moi - je prendrai une bibliothèque sur une fonction copier-coller n'importe quel jour .. surtout une bibliothèque qu'un projet de taille décente utilise probablement déjà. J'espère que cette réponse obtiendra plus de votes positifs et de visibilité à l'avenir.
Sean Connolly
61

Apache Commons a une classe ArrayUtils, qui a une méthode toPrimitive () qui fait exactement cela.

import org.apache.commons.lang.ArrayUtils;
...
    List<Integer> list = new ArrayList<Integer>();
    list.add(new Integer(1));
    list.add(new Integer(2));
    int[] intArray = ArrayUtils.toPrimitive(list.toArray(new Integer[0]));

Cependant, comme Jon l'a montré, il est assez facile de le faire vous-même au lieu d'utiliser des bibliothèques externes.

Björn
la source
2
Notez que cette approche fera deux copies complètes de la séquence: une Entier [] créée par toArray, et une int [] créée à l'intérieur de toPrimitive. L'autre réponse de Jon crée et remplit uniquement un tableau. Quelque chose à considérer si vous avez de grandes listes et que les performances sont importantes.
paraquat
J'ai mesuré les performances en utilisant ArrayUtils vs java pur et sur de petites listes (<25 éléments) java pur est plus de 100 fois plus rapide. Pour les éléments 3k, le java pur est encore presque 2 fois plus rapide ... (ArrayList <Integer> -> int [])
Oskar Lund
@paraquat & Oskar Lund qui n'est pas vraiment correct. Oui, le code fourni créera deux tableaux, mais pas cette approche . Le problème dans ce code ici est l'utilisation d'un tableau de longueur nulle comme argument. Le code source ArrayList.toArray montre que si le contenu convient, le tableau d'origine sera utilisé. Je pense que dans une comparaison juste, vous trouverez que cette méthode est aussi efficace (sinon plus) et, bien sûr, moins de code à maintenir.
Sean Connolly
PS: une belle publication connexe
Sean Connolly
1
Quel est le but de la nouvelle Entier [0]?
Adam Hughes
41

Je pense que l'itération à l'aide de l'itérateur de la liste est une meilleure idée, car list.get(i)les performances peuvent être médiocres selon la mise en œuvre de la liste:

private int[] buildIntArray(List<Integer> integers) {
    int[] ints = new int[integers.size()];
    int i = 0;
    for (Integer n : integers) {
        ints[i++] = n;
    }
    return ints;
}
Matthew Willis
la source
6

utiliser Dollar devrait être assez simple:

List<Integer> list = $(5).toList(); // the list 0, 1, 2, 3, 4  
int[] array = $($(list).toArray()).toIntArray();

Je prévois d'améliorer la DSL afin de supprimer l' toArray()appel intermédiaire

dfa
la source
1
Hé, je voulais juste dire que je n'avais jamais vu Dollar auparavant, mais je suis définitivement en train d'essayer mon prochain projet. C'est une astucieuse petite API que vous avez là-bas, continuez votre bon travail :)
Bart Vandendriessche
4

Cela fonctionne bien pour moi :)

Trouvé sur https://www.techiedelight.com/convert-list-integer-array-int/

import java.util.Arrays;
import java.util.List;

class ListUtil
{
    // Program to convert list of integer to array of int in Java
    public static void main(String args[])
    {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

        int[] primitive = list.stream()
                            .mapToInt(Integer::intValue)
                            .toArray();

        System.out.println(Arrays.toString(primitive));
    }
}
angelhernandez
la source
3

Cela m'étonne que nous encourageons les méthodes personnalisées ponctuelles chaque fois qu'une bibliothèque parfaitement bonne et bien utilisée comme Apache Commons a déjà résolu le problème. Bien que la solution soit triviale sinon absurde, il est irresponsable d'encourager un tel comportement en raison de la maintenance et de l'accessibilité à long terme.

Allez avec Apache Commons

Andrew F.
la source
7
Je suis d'accord avec le commentateur précédent. Non seulement vous faites glisser dans Apache Commons, mais cela se traduit facilement en un grand ensemble de dépendances transitives qui doivent également être glissées. Récemment, j'ai pu supprimer un nombre incroyable de dépendances en remplaçant une ligne de code :-( Les ​​dépendances sont coûteuses et écrire un code de base comme celui-ci est une bonne pratique
Peter Kriens
1
D'accord avec @PeterKriens. Si quelque chose, la faute est à Java pour ne pas prendre en charge les conversions simples comme celle-ci dans ses types de données standard
Adam Hughes
3

Si vous utilisez des collections Eclipse , vous pouvez utiliser la collectInt()méthode pour basculer d'un conteneur d'objets vers un conteneur int primitif.

List<Integer> integers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
MutableIntList intList =
  ListAdapter.adapt(integers).collectInt(i -> i);
Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, intList.toArray());

Si vous pouvez convertir votre ArrayListen un FastList, vous pouvez vous débarrasser de l'adaptateur.

Assert.assertArrayEquals(
  new int[]{1, 2, 3, 4, 5},
  Lists.mutable.with(1, 2, 3, 4, 5)
    .collectInt(i -> i).toArray());

Remarque: je suis un committer pour les collections Eclipse.

Craig P. Motlin
la source
3

Java 8:

int[] intArr = Arrays.stream(integerList).mapToInt(i->i).toArray();
EssaidiM
la source
2

Arrays.setAll ()

    List<Integer> x = new ArrayList<>(Arrays.asList(7, 9, 13));
    int[] n = new int[x.size()];
    Arrays.setAll(n, x::get);

    System.out.println("Array of primitive ints: " + Arrays.toString(n));

Production:

Tableau d'entiers primitifs: [7, 9, 13]

Les mêmes œuvres pour un tableau de longou double, mais pas pour les tableaux de boolean, char, byte, shortou float. Si vous avez une liste vraiment énorme, il existe même une parallelSetAllméthode que vous pouvez utiliser à la place.

Pour moi, c'est assez bon et assez élancé pour que je ne veuille pas obtenir une bibliothèque externe ni utiliser de flux pour cela.

Lien de documentation: Arrays.setAll(int[], IntUnaryOperator)

Ole VV
la source
1

Vous pouvez simplement le copier dans un tableau:

int[] arr = new int[list.size()];
for(int i = 0; i < list.size(); i++) {
    arr[i] = list.get(i);
}

Pas trop de fantaisie; mais bon ça marche ...

sagiksp
la source
1

Une solution monoligne très simple est:

Integer[] i = arrlist.stream().toArray(Integer[]::new);
PramodG
la source
0

Ce segment de code fonctionne pour moi, essayez ceci:

Integer[] arr = x.toArray(new Integer[x.size()]);

Il convient de mentionner ArrayList devrait être déclaré comme suit:

ArrayList<Integer> list = new ArrayList<>();
user3444748
la source
5
Bonjour juste un petit rappel que OP veut un tableau primitif et non un tableau d'objets.
OLIVER.KOO
3
Int primitif pas encapsuleur Entier!
Bartzilla
-4
   List<Integer> list = new ArrayList<Integer>();

    list.add(1);
    list.add(2);

    int[] result = null;
    StringBuffer strBuffer = new StringBuffer();
    for (Object o : list) {
        strBuffer.append(o);
        result = new int[] { Integer.parseInt(strBuffer.toString()) };
        for (Integer i : result) {
            System.out.println(i);
        }
        strBuffer.delete(0, strBuffer.length());
    }
CodeMadness
la source
1
Cette réponse ne fonctionne pas, elle renvoie un tableau avec un seul élément au lieu de plusieurs éléments.
Mysticial
Pourquoi utiliser un StringBuffer? Pourquoi convertir l'entier en une chaîne, puis en un entier, puis en un int puis en un entier à nouveau? Pourquoi utiliser un tableau contenant un seul élément et pourquoi boucler sur ce tableau à un seul élément lorsqu'il ne contient qu'un seul élément? Pourquoi convertir les entiers en objets dans la boucle externe? Il y a tellement de questions ici. @CodeMadness est-il juste un compte troll?
Victor Zamanian
-5
Integer[] arr = (Integer[]) x.toArray(new Integer[x.size()]);

accès arrcomme d'habitude int[].

snn
la source
5
cela ne répond pas à la question, la question portait sur la conversion en type primitif (int)
Asaf