Converti una serie di long primitivi in ​​un elenco di long


138

Questa potrebbe essere una specie di domanda facile, da headdesk, ma il mio primo tentativo sorprendentemente fallì completamente. Volevo prendere una serie di desideri primitivi e trasformarlo in un elenco, che ho cercato di fare in questo modo:

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

Qual è il modo giusto per farlo?


6
Penso che abbiamo avuto la stessa domanda per gli ints, no?
Tom Hawtin - tackline

Risposte:


115

Ho trovato conveniente usare apache commons lang ArrayUtils ( JavaDoc , dipendenza Maven )

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

ha anche l'API inversa

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

EDIT: aggiornato per fornire una conversione completa in un elenco come suggerito da commenti e altre correzioni.


3
Considerando che questo crea una serie di Long, non un Elenco , non risponde alla domanda di OP e ottiene il mio voto negativo. Come diamine ha ottenuto 56 voti positivi e l'ambita "spunta" ???
user949300,

7
Perché le persone possono facilmente farlo Arrays.asList(ArrayUtils.toObject(input))probabilmente.
Eran Medan,

Sono d'accordo con @ user949300. Questo non risponde alla domanda.
dev4life,

1
Questa risposta dovrebbe essere aggiornata per fornire una conversione completa in un elenco. Tuttavia, è un passo efficace verso la soluzione.
Jim Jeffers,

2
@JimJeffers - grazie, aggiornato per includere la conversione completa. Dato che l'OP è stato incluso List<Long> = Arrays.asList(inputBoxed)nella loro domanda, ho trovato ridondante ripeterlo perché pensavo fosse ovvio, immagino di aver sbagliato ...
Eran Medan,

114

Da Java 8 ora puoi usare gli stream per questo:

long[] arr = {1,2,3,4};
List<Long> list = Arrays.stream(arr).boxed().collect(Collectors.toList());

7
Ben fatto! Sfortunatamente, e in qualche modo misteriosamente, la streamfunzione è definita solo per int[], long[]e double[].
Norswap,

1
In alternativa, potresti usare LongStream.of(arr).boxed()....
aioobe,

2
Arrays.stream(arr).boxed().collect(Collectors.toList());Sfortunatamente questo può solo tornareList<Object>
Senthilkumar Annadurai,

Nessuna libreria ingombrante per un compito semplice, nessun loop. Bella risposta.
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}));

5
Una spiegazione di ciò che fa e se si tratta di una libreria di terze parti sarebbe utile.
IgorGanapolsky

35

hallidave e jpalecek hanno l'idea giusta - iterando su un array - ma non sfruttano una funzionalità fornita da ArrayList: poiché in questo caso la dimensione dell'elenco è nota , dovresti specificarla quando crei il file ArrayList.

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

In questo modo, non vengono creati array non necessari solo per essere scartati dal ArrayListperché si rivelano troppo corti e non vengono sprecati "slot" vuoti perché ArrayListsovrastimati i suoi requisiti di spazio. Naturalmente, se si continua ad aggiungere elementi all'elenco, sarà necessario un nuovo array di supporto.


1
Tendo a tralasciare le specifiche di lunghezza a meno che non sia dimostrato che il codice faccia parte di un hot spot delle prestazioni o che ci si aspetti che l'array sia estremamente grande. Penso che tralasciando la lunghezza renda il codice leggermente più leggibile.
hallidave,

19

Un po 'più prolisso, ma funziona:

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

Nel tuo esempio sembra che Arrays.asList () stia interpretando l'input come un elenco di matrici [] lunghe anziché un elenco di Long. Un po 'sorprendente, di sicuro. In questo caso, l'auto boxing non funziona nel modo desiderato.


17

Come altra possibilità, la libreria Guava fornisce questo come Longs.asList(), con classi di utilità simili per gli altri tipi primitivi.

import com.google.common.primitives.Longs;

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

7

No, non esiste una conversione automatica da array di tipo primitivo a array dei loro tipi di riferimento inscatolati. Puoi solo fare

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

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

7

La domanda è stata posta su come trasformare un array in un elenco. La maggior parte delle risposte finora ha mostrato come creare un nuovo elenco con gli stessi contenuti dell'array o riferito a librerie di terze parti. Tuttavia, esistono opzioni integrate semplici per questo tipo di conversione. Alcuni di essi sono già stati delineati in altre risposte (ad esempio questo ). Ma vorrei sottolineare ed elaborare alcuni gradi di libertà per l'implementazione qui, e mostrare i potenziali benefici, svantaggi e avvertenze.

Ci sono almeno due importanti distinzioni da fare:

  • Se l'elenco risultante dovrebbe essere una vista sull'array o se dovrebbe essere un nuovo elenco
  • Se l'elenco risultante dovrebbe essere modificabile o meno

Le opzioni verranno riassunte qui rapidamente e un fondo di esempio completo viene mostrato in fondo a questa risposta.


Creazione di un nuovo elenco anziché creazione di una vista sull'array

Quando il risultato dovrebbe essere un nuovo elenco, è possibile utilizzare uno degli approcci delle altre risposte:

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

Ma bisogna considerare gli svantaggi di questo: un array con 1000000 longvalori occuperà circa 8 Megabyte di memoria. Il nuovo elenco occuperà anche circa 8 Megabyte. E, naturalmente, l'intero array deve essere attraversato durante la creazione di questo elenco. In molti casi, la creazione di un nuovo elenco non è semplicemente necessaria. È invece sufficiente creare una vista sull'array:

// 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);

(Vedi l'esempio in basso per un'implementazione del toListmetodo)

L'implicazione di avere una vista sull'array è che le modifiche nell'array saranno visibili nell'elenco:

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!

Fortunatamente, la creazione di una copia (ovvero un nuovo elenco non interessato dalle modifiche nell'array) dalla vista è banale:

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

Ora, questa è una copia vera, equivalente a ciò che si ottiene con la soluzione basata sul flusso mostrata sopra.


Creazione di una vista modificabile o una vista non modificabile

In molti casi, sarà sufficiente quando l'elenco è di sola lettura . Il contenuto dell'elenco risultante spesso non verrà modificato, ma passerà solo all'elaborazione a valle che legge solo l'elenco.

Consentire la modifica dell'elenco solleva alcune domande:

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?

È possibile creare una vista elenco sull'array che è modificabile . Ciò significa che le modifiche nell'elenco, come l'impostazione di un nuovo valore su un determinato indice, saranno visibili nell'array.

Ma non è possibile creare una vista elenco strutturalmente modificabile . Ciò significa che non è possibile eseguire operazioni che incidono sulla dimensione dell'elenco. Questo semplicemente perché la dimensione dell'array sottostante non può essere modificata.


Di seguito è riportato un MCVE che mostra le diverse opzioni di implementazione e i possibili modi di utilizzare gli elenchi risultanti:

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

}

L'output dell'esempio è mostrato qui:

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

6

Un altro modo con Java 8.

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

6

Sto scrivendo una piccola libreria per questi problemi:

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

Nel caso ti interessi controlla qui .


bella biblioteca! all'inizio, non ero sicuro che fosse Java ... Mi piace lo stile JQuery
Yanick Rochon,

4

Un altro modo con Java 8.

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

1
Quando ho restituito la lista (non assegnandola), ho scoperto che dovevo fare:Arrays.stream(a).boxed().collect(Collectors.<Long>toList());
Jon il

1
Questo è identico a questa risposta esistente .
Pang

3

Combinando le risposte di Pavel e Tom otteniamo questo

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

2

Se desideri una semantica simile a Arrays.asListquella, dovrai scrivere (o usare l'implementazione del cliente di qualcun altro) di List(probabilmente attraverso AbstractList. Dovrebbe avere la stessa implementazione di Arrays.asList, solo i valori box e unbox.


2

Puoi usare transmorph :

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

Funziona anche se source è un array di ints, ad esempio.


2

So che questa domanda è abbastanza vecchia, ma ... puoi anche scrivere il tuo metodo di conversione:

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

Dopo averlo incluso usando l'importazione statica, i possibili utilizzi potrebbero essere:

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

o

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

2
per quanto riguarda catch (ArrayIndexOutOfBoundsException ex) { /* Finished getting array elements */ }:, sei una persona terribile.
Brandon Yarbrough,

Ehi, amico, grazie per quello! La tua ironica osservazione mi ha fatto trovare una soluzione migliore: ottenere la lunghezza dell'array tramite Array.getLength ().
Pavel Netesa,

1
Fantastico! Sono contento che il mio atteggiamento sardonico abbia portato a progressi invece che solo a cattivi sentimenti generali tutt'intorno :) Davvero, non è una buona idea usare le eccezioni se non in condizioni molto insolite. Sono sorprendentemente costosi da creare. Questa nuova versione è molto, MOLTO più veloce.
Brandon Yarbrough,

1

Mentre è possibile creare un nuovo elenco e aggiungere tutti i valori (tramite for loop o stream), ho lavorato su array molto grandi e ho ottenuto prestazioni scadenti. Pertanto ho creato la mia classe wrapper di array primitiva facile da usare.

Esempio:

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

Scarica qui: https://github.com/Sf298/Sauds-Toolbox/blob/master/src/main/java/PrimitiveArrayWrapper/PrimitiveList.java

NOTA: non l'ho ancora testato completamente, quindi fatemi sapere se trovate bug / problemi.


0

Puoi usarlo LongStreamper questo

List<Long> longs = LongStream.of(new long[]{1L, 2L, 3L}).boxed()
                             .collect(Collectors.toList());
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.