Convertir un tableau de longs primitifs en une liste de longs

138

C'est peut-être une question un peu facile, du headdesk, mais ma première tentative a étonnamment échoué complètement. 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 procéder?

Brandon Yarbrough
la source
6
Je pense que nous avons eu la même question pour les ints, n'est-ce pas?
Tom Hawtin - tackline

Réponses:

115

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.

Eran Medan
la source
3
Considérant que cela crée un tableau de Longs, pas une liste , cela ne répond pas à la question de OP et obtient mon vote défavorable. Comment diable cela a-t-il obtenu 56 votes positifs et le "chèque" convoité ???
user949300
7
Parce que les gens peuvent facilement le faire Arrays.asList(ArrayUtils.toObject(input))probablement.
Eran Medan
Je suis d'accord avec @ user949300. Cela ne répond pas à la question.
dev4life
1
Cette réponse doit être mise à jour pour fournir une conversion complète en liste. Cependant, c'est une étape efficace vers la solution.
Jim Jeffers
2
@JimJeffers - merci, mise à jour pour inclure la conversion complète. Depuis que le PO a inclus List<Long> = Arrays.asList(inputBoxed)dans leur question, j'ai trouvé qu'il était redondant de le répéter car je pensais que c'était évident, je suppose que j'avais tort ...
Eran Medan
114

Depuis Java 8, vous pouvez désormais utiliser des flux pour cela:

long[] arr = {1,2,3,4};
List<Long> list = Arrays.stream(arr).boxed().collect(Collectors.toList());
Marcinj
la source
7
Joli! Malheureusement, et quelque peu mystérieusement, la streamfonction n'est définie que pour int[], long[]et double[].
Norswap
1
Vous pouvez également utiliser LongStream.of(arr).boxed()....
aioobe
2
Arrays.stream(arr).boxed().collect(Collectors.toList());Malheureusement, cela ne peut que revenirList<Object>
Senthilkumar Annadurai
Pas de bibliothèques encombrantes pour une tâche simple, pas de boucles. Très bonne réponse.
Alex Quilliam
37
import java.util.Arrays;
import org.apache.commons.lang.ArrayUtils;

List<Long> longs = Arrays.asList(ArrayUtils.toObject(new long[] {1,2,3,4}));
Marco Pelegrini
la source
5
Une explication de ce que cela fait et s'il s'agit d'une bibliothèque tierce serait utile.
IgorGanapolsky
35

hallidave et jpalecek ont la bonne idée - itérer sur un tableau - mais ils ne tirent pas parti d'une fonctionnalité fournie par ArrayList: puisque 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éé uniquement pour être rejeté par le ArrayListcar il s'avère trop court, et aucun «emplacement» vide n'est gaspillé parce qu'il a ArrayListsurestimé ses besoins en espace. Bien sûr, si vous continuez à ajouter des éléments à la liste, un nouveau tableau de sauvegarde sera nécessaire.

Erickson
la source
1
J'ai tendance à omettre la spécification de longueur à moins que le code ne soit prouvé comme faisant partie d'un point chaud de performance ou que le tableau soit censé être extrêmement grand. Je pense que laisser de côté la longueur rend le code un peu plus lisible.
hallidave
19

Un peu plus verbeux, mais cela fonctionne:

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

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

hallidave
la source
17

Comme autre possibilité, la bibliothèque Guava fournit cela comme Longs.asList(), avec des classes utilitaires similaires pour les autres types primitifs.

import com.google.common.primitives.Longs;

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

Non, il n'y a pas de conversion automatique du tableau de type primitif au tableau de leurs types de référence encadrés. Tu peux seulement faire

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

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

La question demandait comment transformer un tableau en liste. La plupart des réponses à ce jour ont montré comment créer une nouvelle liste 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. Certains d'entre eux ont déjà été esquissés dans d'autres réponses (par exemple celle-ci ). Mais j'aimerais souligner et élaborer certains degrés de liberté pour la mise en œuvre ici, et montrer les avantages potentiels, les inconvénients et les mises en garde.

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 nouvelle liste
  • Si la liste résultante doit être modifiable ou non

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


Créer une nouvelle liste ou créer une vue sur la baie

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

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

Mais il faut tenir compte des inconvénients de cette opération: un tableau avec 1000000 longvaleurs occupera environ 8 mégaoctets de mémoire. La nouvelle liste occupera également 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 une vue 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 toListméthode)

L'implication d'avoir une vue sur le tableau est que les changements 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 (c'est-à-dire une nouvelle liste qui n'est pas affectée par les modifications du tableau) à partir de la vue est trivial:

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

Maintenant, il s'agit d'une copie fidèle, équivalente à ce qui est réalisé avec la solution basée sur le flux présentée ci-dessus.


Créer une vue modifiable ou une vue non modifiable

Dans de nombreux cas, cela suffira lorsque la liste est en lecture seule . Le contenu de la liste résultante ne sera souvent pas modifié, mais uniquement 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 de liste sur le tableau qui est modifiable . Cela signifie que les changements dans la liste, comme 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 de liste structurellement modifiable . Cela signifie qu'il n'est pas possible d'effectuer des opérations qui affectent la taille de la liste. C'est simplement parce que la taille du tableau sous-jacent ne peut pas être modifiée.


Ce qui suit est un MCVE montrant les différentes options d'implémentation 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;
import java.util.RandomAccess;

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);
        class ResultList extends AbstractList<Long> implements RandomAccess
        {
            @Override
            public Long get(int index)
            {
                return array[index];
            }

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

    /**
     * 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);
        class ResultList extends AbstractList<Long> implements RandomAccess
        {
            @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;
            }
        };
        return new ResultList();
    }

}

La sortie de l'exemple est affiché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
Marco13
la source
6

Une autre façon avec Java 8.

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

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

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

Dans le cas où vous vous en souciez, vérifiez-le ici .

dfa
la source
belle bibliothèque! au début, je n'étais pas sûr que c'était Java ... J'aime le style JQuery
Yanick Rochon
4

Une autre façon avec Java 8.

final long[] a = new long[]{1L, 2L};
final List<Long> l = Arrays.stream(a).boxed().collect(Collectors.toList());
Jin Kwon
la source
1
En renvoyant la liste (sans l'attribuer), j'ai trouvé que je devais faire:Arrays.stream(a).boxed().collect(Collectors.<Long>toList());
Jon
1
Ceci est identique à cette réponse existante .
Pang
3

En combinant les réponses de Pavel et 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);
            }
        };
    }
Duncan McGregor
la source
2

Si vous voulez une sémantique similaire, Arrays.asListvous devrez écrire (ou utiliser l'implémentation client de quelqu'un d'autre) de List(probablement via AbstractList. Elle devrait avoir à peu près la même implémentation que les Arrays.asListvaleurs box et unbox uniquement).

Tom Hawtin - Tacle
la source
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 également si la source est un tableau d'entiers par exemple.

cchabanois
la source
2

Je sais que cette question est assez ancienne, mais ... vous pouvez également é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 de l'importation statique, les utilisations possibles peuvent ê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);
Pavel Netesa
la source
2
concernant:, catch (ArrayIndexOutOfBoundsException ex) { /* Finished getting array elements */ }vous êtes une personne terrible.
Brandon Yarbrough
Hé, mec, merci pour ça! Votre remarque ironique m'a amené à trouver une meilleure solution - obtenir la longueur du tableau via Array.getLength ().
Pavel Netesa
1
Fantastique! Je suis content que mon attitude sardonique ait conduit à des progrès au lieu de simples mauvais sentiments tout autour :) Vraiment, ce n'est pas une bonne idée d'utiliser des exceptions sauf dans des conditions très inhabituelles. Leur création est étonnamment coûteuse. Cette nouvelle version est beaucoup, BEAUCOUP plus rapide.
Brandon Yarbrough
1

Bien qu'il soit possible de créer une nouvelle liste et d'y ajouter toutes les valeurs (via une boucle for ou des flux), j'ai travaillé sur de très gros tableaux et j'obtiens de mauvaises performances. Par conséquent, j'ai créé ma propre classe de wrapper de tableau primitif 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 entièrement testé, alors faites-moi savoir si vous trouvez des bogues / problèmes.

sf298
la source
0

Vous pouvez utiliser LongStreampour cela

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