Converter uma matriz de longos primitivos em uma lista de longos

138

Isso pode ser um pouco fácil, tipo de pergunta na mesa, mas minha primeira tentativa surpreendentemente falhou completamente no trabalho. Eu queria pegar uma matriz de longos primitivos e transformá-lo em uma lista, que tentei fazer assim:

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

Qual é o caminho certo para fazer isso?

Brandon Yarbrough
fonte
6
Acho que tivemos a mesma pergunta para ints, não é?
Tom Hawtin - tackline

Respostas:

115

Achei conveniente usar o apache commons lang ArrayUtils ( JavaDoc , dependência do Maven )

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

ele também tem a API reversa

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

EDIT: atualizado para fornecer uma conversão completa em uma lista, conforme sugerido por comentários e outras correções.

Eran Medan
fonte
3
Considerando que isso cria uma variedade de Longs, não uma Lista , não responde à pergunta do OP e recebe meu voto negativo. Como diabos isso conseguiu 56 votos positivos e o cobiçado "cheque" ???
user949300
7
Porque as pessoas podem facilmente fazer isso Arrays.asList(ArrayUtils.toObject(input))provavelmente.
Eran Medan
Eu concordo com @ user949300. Isso não responde à pergunta.
Dev4life 19/06/15
1
Esta resposta deve ser atualizada para fornecer uma conversão completa em uma lista. No entanto, é um passo eficiente em direção à solução.
21715 Jim Jimers
2
@ JimJeffers - obrigado, atualizado para incluir a conversão completa. Uma vez que o OP incluído List<Long> = Arrays.asList(inputBoxed)em sua pergunta que eu achei redundante repeti-la como eu pensei que era óbvio, eu acho que eu estava errado ...
Eran Medan
114

Desde o Java 8, agora você pode usar fluxos para isso:

long[] arr = {1,2,3,4};
List<Long> list = Arrays.stream(arr).boxed().collect(Collectors.toList());
marcinj
fonte
7
Agradável! Infelizmente, e um tanto misteriosamente, a streamfunção é definida apenas para int[], long[]e double[].
Norswap
1
Como alternativa, você pode usar LongStream.of(arr).boxed()....
aioobe
2
Arrays.stream(arr).boxed().collect(Collectors.toList());Infelizmente isso só pode voltar #List<Object>
Senthilkumar Annadurai 28/11
Sem bibliotecas volumosas para uma tarefa simples, sem loops. Ótima resposta.
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
fonte
5
Uma explicação sobre o que isso faz e se é uma biblioteca de terceiros seria útil.
IgorGanapolsky 17/03/19
35

hallidave e jpalecek têm a idéia certa - iterando sobre uma matriz - mas não tiram vantagem de um recurso fornecido por ArrayList: como o tamanho da lista é conhecido nesse caso, você deve especificá-lo quando criar o ArrayList.

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

Dessa forma, nenhuma matriz desnecessária é criada apenas para ser descartada pelo ArrayListporque ela é muito curta e nenhum "slot" vazio é desperdiçado porque ArrayListsuperestimou seus requisitos de espaço. Obviamente, se você continuar adicionando elementos à lista, será necessária uma nova matriz de apoio.

erickson
fonte
1
Costumo deixar de fora a especificação de comprimento, a menos que se prove que o código faz parte de um hot spot de desempenho ou se espera que a matriz seja extremamente grande. Eu acho que deixar de fora o comprimento torna o código um pouco mais legível.
Hallidave 18/04/09
19

Um pouco mais detalhado, mas isso funciona:

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

No seu exemplo, parece que Arrays.asList () está interpretando a entrada como lista de matrizes longas [] em vez de uma lista de Longs. Um pouco surpreendente, com certeza. A autoboxing simplesmente não funciona da maneira que você deseja neste caso.

hallidave
fonte
17

Como outra possibilidade, a biblioteca Guava fornece isso como Longs.asList(), com classes de utilidade semelhantes para os outros tipos primitivos.

import com.google.common.primitives.Longs;

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

Não, não há conversão automática de matriz do tipo primitivo para matriz de seus tipos de referência em caixa. Você só pode fazer

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

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

A pergunta foi feita sobre como transformar uma matriz em uma lista. Até agora, a maioria das respostas mostrou como criar uma nova lista com o mesmo conteúdo da matriz ou referir-se a bibliotecas de terceiros. No entanto, existem opções simples e integradas para esse tipo de conversão. Alguns deles já foram esboçados em outras respostas (por exemplo, esta ). Mas eu gostaria de salientar e elaborar certos graus de liberdade para a implementação aqui e mostrar os possíveis benefícios, desvantagens e advertências.

Há pelo menos duas distinções importantes a serem feitas:

  • Se a lista resultante deve ser uma exibição na matriz ou se deve ser uma nova lista
  • Se a lista resultante deve ser modificável ou não

As opções serão resumidas aqui rapidamente, e um programa de exemplo completo é mostrado na parte inferior desta resposta.


Criando uma nova lista versus criando uma exibição na matriz

Quando o resultado deve ser uma nova lista, uma das abordagens das outras respostas pode ser usada:

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

Mas deve-se considerar as desvantagens de fazer isso: uma matriz com longvalores de 1000000 ocupará aproximadamente 8 megabytes de memória. A nova lista também ocupará cerca de 8 megabytes. E, claro, a matriz completa deve ser percorrida ao criar esta lista. Em muitos casos, a criação de uma nova lista simplesmente não é necessária. Em vez disso, é suficiente criar uma exibição na matriz:

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

(Veja o exemplo na parte inferior para uma implementação do toListmétodo)

A implicação de ter uma visualização na matriz é que as alterações na matriz serão visíveis na lista:

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!

Felizmente, a criação de uma cópia (ou seja, uma nova lista que não é afetada por modificações na matriz) a partir da exibição é trivial:

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

Agora, esta é uma cópia verdadeira, equivalente ao que é alcançado com a solução baseada em fluxo que foi mostrada acima.


Criando uma visão modificável ou uma visão não modificável

Em muitos casos, será suficiente quando a lista for somente leitura . O conteúdo da lista resultante geralmente não será modificado, mas passado apenas para o processamento downstream que apenas lê a lista.

Permitir modificações da lista levanta algumas questões:

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?

É possível criar uma exibição de lista na matriz que seja modificável . Isso significa que as alterações na lista, como definir um novo valor em um determinado índice, serão visíveis na matriz.

Mas não é possível criar uma exibição de lista estruturalmente modificável . Isso significa que não é possível executar operações que afetam o tamanho da lista. Isso ocorre simplesmente porque o tamanho da matriz subjacente não pode ser alterado.


A seguir, é apresentado um MCVE, mostrando as diferentes opções de implementação e as possíveis maneiras de usar as listas resultantes:

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

}

A saída do exemplo é mostrada aqui:

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
fonte
6

Outra maneira com o Java 8.

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

Estou escrevendo uma pequena biblioteca para esses problemas:

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

Caso você se preocupe, verifique aqui .

dfa
fonte
boa biblioteca! em primeiro lugar, eu não tinha certeza que era Java ... Eu gosto do estilo JQuery
Yanick Rochon
4

Outra maneira com o Java 8.

final long[] a = new long[]{1L, 2L};
final List<Long> l = Arrays.stream(a).boxed().collect(Collectors.toList());
Jin Kwon
fonte
1
Ao retornar a lista (não a atribuí-la), descobri que tinha que fazer:Arrays.stream(a).boxed().collect(Collectors.<Long>toList());
Jon
1
Isso é idêntico a esta resposta existente .
Pang
3

Combinando as respostas de Pavel e Tom, obtemos isso

   @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
fonte
2

Se você deseja uma semântica semelhante Arrays.asList, precisará escrever (ou usar a implementação de outra pessoa) do cliente List(provavelmente através dela AbstractList. Ele deve ter a mesma implementação que Arrays.asListapenas valores de caixa e unbox.

Tom Hawtin - linha de orientação
fonte
2

Você pode usar o transmorph :

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

Também funciona se fonte é uma matriz de entradas, por exemplo.

cchabanois
fonte
2

Eu sei que esta pergunta é antiga o suficiente, mas ... você também pode escrever seu próprio método de conversão:

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

Depois de incluí-lo usando a importação estática, os usos possíveis podem ser:

    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
fonte
2
em relação a:, catch (ArrayIndexOutOfBoundsException ex) { /* Finished getting array elements */ }você é uma pessoa terrível.
Brandon Yarbrough
Ei, cara, obrigado por isso! Sua observação irônica me fez encontrar uma solução melhor - obter o comprimento da matriz através de Array.getLength ().
Pavel Netesa 16/10/12
1
Fantástico! Fico feliz que minha atitude sardônica tenha levado ao progresso, em vez de apenas sentimentos ruins em toda parte :) Realmente, não é uma boa idéia usar exceções, exceto em condições muito incomuns. Eles são surpreendentemente caros para criar. Esta nova versão é muito, muito mais rápida.
precisa
1

Embora seja possível criar uma nova lista e adicionar todos os valores a ela (via loop ou fluxos), tenho trabalhado em matrizes realmente grandes e obtém desempenho ruim. Portanto, criei minha própria classe de wrapper de matriz primitiva fácil de usar.

Exemplo:

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

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

OBSERVAÇÃO: ainda não o testei completamente, informe-me se encontrar algum erro / problema.

sf298
fonte
0

Você pode usar LongStreampara isso

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