web-dev-qa-db-fra.com

Convertir un tableau de longs primitifs en une liste de longs

C’est peut-être une question de tête facile, mais ma première tentative a complètement échoué. Je voulais prendre un tableau de longs primitifs et le transformer en une liste, ce que j'ai essayé de faire comme ceci:

long[] input = someAPI.getSomeLongs();
List<Long> inputAsList = Arrays.asList(input); //Total failure to even compile!

Quelle est la bonne façon de faire cela?

131
Brandon Yarbrough

J'ai trouvé pratique d'utiliser Apache commons lang ArrayUtils ( JavaDoc , dépendance Maven )

import org.Apache.commons.lang3.ArrayUtils;
...
long[] input = someAPI.getSomeLongs();
Long[] inputBoxed = ArrayUtils.toObject(input);
List<Long> inputAsList = Arrays.asList(inputBoxed);

il a également l'API inverse

long[] backToPrimitive = ArrayUtils.toPrimitive(objectArray);

EDIT: mis à jour pour fournir une conversion complète en liste comme suggéré par les commentaires et autres correctifs.

107
Eran Medan

Depuis Java 8, vous pouvez maintenant utiliser des flux pour cela:

long[] arr = {1,2,3,4};
List<Long> list = Arrays.stream(arr).boxed().collect(Collectors.toList());
99
marcinj
import Java.util.Arrays;
import org.Apache.commons.lang.ArrayUtils;

List<Long> longs = Arrays.asList(ArrayUtils.toObject(new long[] {1,2,3,4}));
37
Marco Pelegrini

hallidave et jpalecek ont la bonne idée - itérer sur un tableau - mais ne tirent pas parti d'une fonctionnalité fournie par ArrayList: since la taille de la liste est connue . Dans ce cas, vous devez la spécifier lorsque vous créez le ArrayList.

List<Long> list = new ArrayList<Long>(input.length);
for (long n : input)
  list.add(n);

De cette façon, aucun tableau inutile n'est créé pour être simplement jeté par le ArrayList car il s'avère trop court, et aucun "emplacement" vide n'est gaspillé car ArrayList a surestimé ses besoins en espace. Bien sûr, si vous continuez à ajouter des éléments à la liste, un nouveau tableau de sauvegarde sera nécessaire.

34
erickson

Un peu plus verbeux, mais ça marche:

    List<Long> list = new ArrayList<Long>();
    for (long value : input) {
        list.add(value);
    }

Dans votre exemple, il apparaît que Arrays.asList () interprète l'entrée en tant que liste de longs tableaux [] au lieu d'une liste de longs. Un peu surprenant, bien sûr. La sélection automatique ne fonctionne tout simplement pas comme vous le souhaitez dans ce cas.

19
hallidave

Comme autre possibilité, la bibliothèque Guava fournit ceci sous la forme Longs.asList() , avec des classes d’utilitaires similaires pour les autres types primitifs.

import com.google.common.primitives.Longs;

long[] input = someAPI.getSomeLongs();
List<Long> output = Longs.asList(input);
17
Trevor Robinson

Non, il n'y a pas de conversion automatique d'un tableau de type primitif en un tableau de leurs types de référence en boîte. Vous pouvez seulement faire

long[] input = someAPI.getSomeLongs();
List<Long> lst = new ArrayList<Long>();

for(long l : input) lst.add(l);
7
jpalecek

J'écris une petite bibliothèque pour ces problèmes:

long[] input = someAPI.getSomeLongs();
List<Long> = $(input).toList();

Dans le cas où vous voudriez le vérifier ici .

6
dfa

Une autre façon avec Java 8.

long[] input = someAPI.getSomeLongs();
LongStream.of(input).boxed().collect(Collectors.toList()));
6
ravenskater

La question demandait comment transformer un tableau en liste. Jusqu'à présent, la plupart des réponses montraient comment créer une liste nouvelle avec le même contenu que le tableau ou faisant référence à des bibliothèques tierces. Cependant, il existe des options simples et intégrées pour ce type de conversion. Certaines d’entre elles ont déjà été esquissées dans d’autres réponses (par exemple, celle-ci ). Mais j'aimerais souligner et préciser certains degrés de liberté pour la mise en œuvre ici et montrer les avantages, inconvénients et mises en garde potentiels.

Il y a au moins deux distinctions importantes à faire:

  • Si la liste résultante doit être une vue sur le tableau ou si elle doit être une liste new
  • Si la liste résultante doit être modifiable ou non

Les options seront résumées ici rapidement, et un exemple complet de programme est présenté au bas de cette réponse.


Création d'une nouvelle liste versus création d'un vue sur le tablea

Lorsque le résultat doit être une liste new, l'une des approches des autres réponses peut être utilisée:

List<Long> list = Arrays.stream(array).boxed().collect(Collectors.toList());

Mais on devrait considérer les inconvénients de ceci: Un tableau avec 1000000 long valeurs occupera environ 8 Mo de mémoire. La nouvelle liste va aussi occuper environ 8 mégaoctets. Et bien sûr, le tableau complet doit être parcouru lors de la création de cette liste. Dans de nombreux cas, la création d’une nouvelle liste n’est tout simplement pas nécessaire. Au lieu de cela, il suffit de créer un view sur le tableau:

// This occupies ca. 8 MB
long array[] = { /* 1 million elements */ }

// Properly implemented, this list will only occupy a few bytes,
// and the array does NOT have to be traversed, meaning that this
// operation has nearly ZERO memory- and processing overhead:
List<Long> list = asList(array);

(Voir l'exemple en bas pour une implémentation de la méthode toList.)

L'implication d'avoir un view sur le tableau signifie que les modifications dans le tableau seront visibles dans la liste:

long array[] = { 12, 34, 56, 78 };
List<Long> list = asList(array);

System.out.println(list.get(1)); // This will print 34

// Modify the array contents:
array[1] = 12345;

System.out.println(list.get(1)); // This will now print 12345!

Heureusement, créer une copie de la vue (c'est-à-dire une liste new qui n'est pas affectée par les modifications apportées au tableau) est simple:

List<Long> copy = new ArrayList<Long>(asList(array));

À présent, il s’agit d’une copie conforme, équivalente à celle obtenue avec la solution basée sur le flux présentée ci-dessus.


Création d'une vue modifiable ou d'une non modifiable vue

Dans de nombreux cas, il suffira que la liste soit en lecture seule. Le contenu de la liste obtenue ne sera souvent pas modifié, mais seulement transmis au traitement en aval qui ne lit que la liste.

Permettre des modifications de la liste soulève quelques questions:

long array[] = { 12, 34, 56, 78 };
List<Long> list = asList(array);

list.set(2, 34567);           // Should this be possible?
System.out.println(array[2]); // Should this print 34567?
list.set(3, null);            // What should happen here?
list.add(99999);              // Should this be possible?

Il est possible de créer une vue liste sur le tableau qui est modifiable. Cela signifie que les modifications dans la liste, telles que la définition d'une nouvelle valeur à un certain index, seront visibles dans le tableau.

Mais il n'est pas possible de créer une vue liste qui est structurellement modifiable. Cela signifie qu'il n'est pas possible d'effectuer des opérations qui affectent le size de la liste. C'est simplement parce que la taille du sous-jacent array ne peut pas être modifiée.


Voici un MCVE montrant les différentes options de mise en oeuvre et les manières possibles d'utiliser les listes résultantes:

import Java.util.AbstractList;
import Java.util.ArrayList;
import Java.util.Arrays;
import Java.util.List;
import Java.util.Objects;

public class PrimitiveArraysAsLists
{
    public static void main(String[] args)
    {
        long array[] = { 12, 34, 56, 78 };

        // Create VIEWS on the given array
        List<Long> list = asList(array);
        List<Long> unmodifiableList = asUnmodifiableList(array);

        // If a NEW list is desired (and not a VIEW on the array), this
        // can be created as well:
        List<Long> copy = new ArrayList<Long>(asList(array));

        System.out.println("array           : " + Arrays.toString(array));
        System.out.println("list            : " + list);
        System.out.println("unmodifiableList: " + unmodifiableList);
        System.out.println("copy            : " + copy);        

        // Modify a value in the array. The changes will be visible
        // in the list and the unmodifiable list, but not in
        // the copy.
        System.out.println("Changing value at index 1 of the array...");
        array[1] = 34567;

        System.out.println("array           : " + Arrays.toString(array));
        System.out.println("list            : " + list);
        System.out.println("unmodifiableList: " + unmodifiableList);
        System.out.println("copy            : " + copy);        

        // Modify a value of the list. The changes will be visible
        // in the array and the unmodifiable list, but not in
        // the copy.
        System.out.println("Changing value at index 2 of the list...");
        list.set(2, 56789L);

        System.out.println("array           : " + Arrays.toString(array));
        System.out.println("list            : " + list);
        System.out.println("unmodifiableList: " + unmodifiableList);
        System.out.println("copy            : " + copy);        


        // Certain operations are not supported:
        try
        {
            // Throws an UnsupportedOperationException: This list is 
            // unmodifiable, because the "set" method is not implemented
            unmodifiableList.set(2, 23456L);
        }
        catch (UnsupportedOperationException e) 
        {
            System.out.println("Expected: " + e);
        }

        try
        {
            // Throws an UnsupportedOperationException: The size of the
            // backing array cannot be changed
            list.add(90L);
        }
        catch (UnsupportedOperationException e) 
        {
            System.out.println("Expected: " + e);
        }


        try
        {
            // Throws a NullPointerException: The value 'null' cannot be  
            // converted to a primitive 'long' value for the underlying array
            list.set(2, null);
        }
        catch (NullPointerException e)
        {
            System.out.println("Expected: " + e);
        }

    }

    /**
     * Returns an unmodifiable view on the given array, as a list.
     * Changes in the given array will be visible in the returned
     * list.
     *  
     * @param array The array
     * @return The list view
     */
    private static List<Long> asUnmodifiableList(long array[])
    {
        Objects.requireNonNull(array);
        return new AbstractList<Long>()
        {
            @Override
            public Long get(int index)
            {
                return array[index];
            }

            @Override
            public int size()
            {
                return array.length;
            }
        };
    }

    /**
     * Returns a view on the given array, as a list. Changes in the given 
     * array will be visible in the returned list, and vice versa. The
     * list does not allow for <i>structural modifications</i>, meaning
     * that it is not possible to change the size of the list.
     *  
     * @param array The array
     * @return The list view
     */
    private static List<Long> asList(long array[])
    {
        Objects.requireNonNull(array);
        return new AbstractList<Long>()
        {
            @Override
            public Long get(int index)
            {
                return array[index];
            }

            @Override
            public Long set(int index, Long element)
            {
                long old = array[index];
                array[index] = element;
                return old;
            }

            @Override
            public int size()
            {
                return array.length;
            }
        };
    }

}

La sortie de l'exemple est montrée ici:

array           : [12, 34, 56, 78]
list            : [12, 34, 56, 78]
unmodifiableList: [12, 34, 56, 78]
copy            : [12, 34, 56, 78]
Changing value at index 1 of the array...
array           : [12, 34567, 56, 78]
list            : [12, 34567, 56, 78]
unmodifiableList: [12, 34567, 56, 78]
copy            : [12, 34, 56, 78]
Changing value at index 2 of the list...
array           : [12, 34567, 56789, 78]
list            : [12, 34567, 56789, 78]
unmodifiableList: [12, 34567, 56789, 78]
copy            : [12, 34, 56, 78]
Expected: Java.lang.UnsupportedOperationException
Expected: Java.lang.UnsupportedOperationException
Expected: Java.lang.NullPointerException
5
Marco13

Un autre moyen avec Java 8.

final long[] a = new long[]{1L, 2L};
final List<Long> l = Arrays.stream(a).boxed().collect(Collectors.toList());
3
Jin Kwon

En combinant les réponses de Pavel et de Tom, nous obtenons ceci.

   @SuppressWarnings("unchecked")
    public static <T> List<T> asList(final Object array) {
        if (!array.getClass().isArray())
            throw new IllegalArgumentException("Not an array");
        return new AbstractList<T>() {
            @Override
            public T get(int index) {
                return (T) Array.get(array, index);
            }

            @Override
            public int size() {
                return Array.getLength(array);
            }
        };
    }
3
Duncan McGregor

Je sais que cette question est assez vieille, mais ... vous pouvez aussi écrire votre propre méthode de conversion:

@SuppressWarnings("unchecked")
public static <T> List<T> toList(Object... items) {

    List<T> list = new ArrayList<T>();

    if (items.length == 1 && items[0].getClass().isArray()) {
        int length = Array.getLength(items[0]);
        for (int i = 0; i < length; i++) {
            Object element = Array.get(items[0], i);
            T item = (T)element;
            list.add(item);
        }
    } else {
        for (Object i : items) {
            T item = (T)i;
            list.add(item);
        }
    }

    return list;
}

Une fois que vous l'avez inclus à l'aide d'une importation statique, les utilisations possibles pourraient être:

    long[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    List<Long> list = toList(array);

ou

    List<Long> list = toList(1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l, 9l);
2
Pavel Netesa

Si vous voulez une sémantique similaire à Arrays.asList alors vous devrez écrire (ou utiliser celui de quelqu'un d'autre) l'implémentation cliente de List (probablement par le biais de AbstractList. Elle devrait avoir à peu près la même implémentation que Arrays.asList, uniquement les valeurs box et unbox.

2

Vous pouvez utiliser transmorph :

Transmorph transmorph = new Transmorph(new DefaultConverters());
List<Long> = transmorph.convert(new long[] {1,2,3,4}, new TypeReference<List<Long>>() {});

Cela fonctionne aussi si source est un tableau d'ints par exemple.

2
cchabanois

Bien qu'il soit possible de créer une nouvelle liste et d'y ajouter toutes les valeurs (via des boucles for ou des flux), j'ai travaillé sur de très grands tableaux et mes performances sont médiocres. Par conséquent, j'ai créé ma propre classe d'encapsuleur de tableaux primitifs facile à utiliser.

Exemple:

long[] arr = new long[] {1,2,3};
PrimativeList<Long> list = PrimativeList.create(arr); // detects long[] and returns PrimativeList<Long>

System.out.println(list.get(1)); // prints: 2
list.set(2, 15);
System.out.println(arr[2]);  // prints: 15

Obtenez-le ici: https://github.com/Sf298/Sauds-Toolbox/blob/master/src/main/Java/PrimitiveArrayWrapper/PrimitiveList.Java

REMARQUE: je ne l'ai pas encore complètement testé, donc laissez-moi savoir si vous trouvez des bogues ou des problèmes.

1
sf298

Vous pouvez utiliser LongStream pour cela

List<Long> longs = LongStream.of(new long[]{1L, 2L, 3L}).boxed()
                             .collect(Collectors.toList());
0
Ritam Chakraborty