Jak przekonwertować ArrayList zawierający liczby całkowite na pierwotną tablicę int?


297

Próbuję przekonwertować ArrayList zawierającą obiekty Integer na pierwotne int [] za pomocą następującego fragmentu kodu, ale generuje błąd czasu kompilacji. Czy można konwertować w Javie?

List<Integer> x =  new ArrayList<Integer>();
int[] n = (int[])x.toArray(int[x.size()]);

10
Nie jest DOKŁADNYM duplikatem tego pytania (choć też niezbyt daleko)
Jonik

1
Tak, jest to ArrayList, „duplikat” dotyczy normalnej tablicy.
Scott McIntyre

3
Jeśli nie potrzebujesz prymitywnych ints, możesz użyć: List<Integer> x = new ArrayList<Integer>(); Integer[] n = x.toArray(new Integer[0]);
Evorlor

Odpowiedzi:


219

Możesz konwertować, ale nie sądzę, że jest coś wbudowanego, aby to zrobić automatycznie:

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

(Pamiętaj, że spowoduje to zgłoszenie wyjątku NullPointerException, jeśli jest w nim którykolwiek integerslub jakikolwiek element null.)

EDYCJA: Jak na komentarze, możesz użyć iteratora listy, aby uniknąć nieprzyjemnych kosztów z listami takimi jak 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;
}

21
Lepszym rozwiązaniem może być iteracja przy użyciu iteratora Listy (z każdym dla każdego), aby uniknąć trafień wydajnościowych na listach, do których dostęp nie jest O (1).
Matthew Willis,

@Matthew: Tak, być może - będzie edytować, aby dać to jako alternatywę.
Jon Skeet,

1
Możesz także wykorzystać fakt, że ArrayList implementuje Iterable (poprzez dziedziczenie Collection) i wykonaj: for (int n: integer) {ret [counter ++] = n; } ... i zainicjuj int counter = 0;
gardarh

8
o wiele łatwiej teraz w Java8:integers.stream().mapToInt(Integer::valueOf).toArray
Manish Patel

241

Jeśli używasz jest też inny sposób, aby to zrobić.

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

Co to robi:

  • uzyskiwanie Stream<Integer> z listy
  • uzyskiwanie IntStreampoprzez mapowanie każdego elementu do siebie (funkcja tożsamości), rozpakowywanie intwartości przechowywanej przez każdy elementInteger obiekt (wykonywane automatycznie od Java 5)
  • uzyskanie tablicy intprzez wywołanietoArray

Można również jawnie wywołać intValueza pomocą odwołania do metody, tj .:

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

Warto również wspomnieć, że możesz dostać, NullPointerExceptionjeśli masz jakieś nullodniesienia na liście. Można tego łatwo uniknąć, dodając warunek filtrowania do potoku strumienia w następujący sposób:

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

Przykład:

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]

Widzę, że można tego użyć dla doubletypów; czy nie ma odpowiedników dla floattypów?
code_dredd,

Widziałeś zalety Java 8, opracowując wyjaśnienie.
Eugene

I właśnie dlatego interfejs API Java 8+ Stream jest piękny.
Pranav A.

67

Google Guava

Google Guava zapewnia dobry sposób na to, dzwoniąc Ints.toArray.

List<Integer> list = ...;
int[] values = Ints.toArray(list);

6
Myślę, że to będzie dla mnie odpowiedź - każdego dnia przejmę bibliotekę zamiast funkcji kopiuj-wklej. Szczególnie bibliotekę, z której prawdopodobnie korzysta już całkiem spory projekt. Mam nadzieję, że ta odpowiedź zyska więcej głosów i będzie bardziej widoczna w przyszłości.
Sean Connolly,

61

Apache Commons ma klasę ArrayUtils, która ma metodę toPrimitive (), która właśnie to robi.

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

Jednak, jak pokazał Jon, dość łatwo jest to zrobić samemu, zamiast korzystać z zewnętrznych bibliotek.


2
Zauważ, że to podejście utworzy dwie kompletne kopie sekwencji: jedną liczbę całkowitą [] utworzoną przez toArray i jedną liczbę całkowitą [] utworzoną wewnątrz toPrimitive. Druga odpowiedź Jona tworzy i wypełnia tylko jedną tablicę. Coś do rozważenia, jeśli masz duże listy, a wydajność jest ważna.
paraquat

Zmierzyłem wydajność za pomocą ArrayUtils w porównaniu z czystą Javą i na małych listach (<25 elementów) czysta Java jest ponad 100 razy szybsza. W przypadku elementów 3k czysta java jest nadal prawie 2 razy szybsza ... (ArrayList <Integer> -> int [])
Oskar Lund

@paraquat i Oskar Lund, które w rzeczywistości nie są poprawne. Tak, podany kod utworzy dwie tablice, ale takie podejście nie. Problemem w tym kodzie jest użycie tablicy o zerowej długości jako argumentu. Że kod źródłowy ArrayList.toArray pokazuje, że jeśli zawartość będzie pasować przy tablicy będą stosowane. Myślę, że w uczciwym porównaniu przekonasz się, że ta metoda jest równie wydajna (jeśli nie większa) i, oczywiście, mniej kodu do utrzymania.
Sean Connolly,


1
Waht jest celem nowej liczby całkowitej [0]?
Adam Hughes,

41

Uważam, że iterowanie przy użyciu iteratora listy jest lepszym pomysłem, ponieważ list.get(i)może mieć niską wydajność w zależności od implementacji listy:

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

6

korzystanie z Dollara powinno być dość proste:

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

Planuję ulepszyć DSL, aby usunąć toArray()połączenie pośrednie


1
Hej, chciałem tylko powiedzieć, że nie widziałem Dollara wcześniej, ale zdecydowanie wypróbuję go w moim następnym projekcie. To fajne małe API, które tam jadycie, kontynuujcie dobrą robotę :)
Bart Vandendriessche

4

Działa mi to dobrze :)

Znalezione na 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));
    }
}

3

Zaskakuje mnie, że zachęcamy do jednorazowych niestandardowych metod, gdy doskonale dobra, dobrze używana biblioteka, taka jak Apache Commons, już rozwiązała problem. Chociaż rozwiązanie jest trywialne, jeśli nie absurdalne, nieodpowiedzialne jest zachęcanie do takiego zachowania ze względu na długoterminową konserwację i dostępność.

Po prostu idź z Apache Commons


7
Zgadzam się z poprzednim komentatorem. Nie tylko przeciągasz w Apache Commons, ale łatwo przekłada się to na duży zestaw zależności przechodnich, które również muszą zostać przeciągnięte. Ostatnio mogłem usunąć niesamowitą liczbę zależności, zastępując jeden wiersz kodu :-( Zależności są kosztowne i pisanie takiego podstawowego kodu jest dobrą praktyką
Peter Kriens

1
Uzgodniony z @PeterKriens. Jeśli już, to wina Javy polega na tym, że nie obsługuje takich prostych konwersji w standardowych typach danych
Adam Hughes

3

Jeśli używasz kolekcji Eclipse , możesz użyć tej collectInt()metody, aby przełączyć się z kontenera obiektów na pierwotny kontener int.

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

Jeśli możesz przekonwertować swój ArrayListna FastList, możesz pozbyć się adaptera.

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

Uwaga: jestem osobą odpowiedzialną za kolekcje Eclipse.


3

Java 8:

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

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

Wynik:

Tablica pierwotnych liczb całkowitych: [7, 9, 13]

Te same prace na tablicy longlub double, ale nie dla tablic boolean, char, byte, shortlub float. Jeśli masz naprawdę ogromną listę, istnieje nawet parallelSetAllmetoda, której możesz użyć zamiast tego.

Dla mnie jest to dobre i wystarczająco elokwentne, że nie chciałbym mieć biblioteki zewnętrznej ani używać do niej strumieni.

Link do dokumentacji: Arrays.setAll(int[], IntUnaryOperator)


1

Możesz po prostu skopiować go do tablicy:

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

Niezbyt fantazyjne; ale hej, to działa ...


1

Bardzo proste jedno-liniowe rozwiązanie to:

Integer[] i = arrlist.stream().toArray(Integer[]::new);

0

Ten segment kodu działa dla mnie, spróbuj tego:

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

Warto wspomnieć, że ArrayList należy zadeklarować w następujący sposób:

ArrayList<Integer> list = new ArrayList<>();

5
Cześć, tylko delikatne przypomnienie, że OP chce prymitywnej tablicy, a nie tablicy Object.
OLIVER.KOO

3
Primitive int not wrapper Integer!
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());
    }

1
Ta odpowiedź nie działa, zwraca tablicę z jednym elementem zamiast wielu elementów.
Tajemniczy

Dlaczego warto korzystać z StringBuffer? Po co konwertować liczbę całkowitą na ciąg, a następnie na liczbę całkowitą, a następnie na liczbę całkowitą, a następnie ponownie na liczbę całkowitą? Po co używać tablicy z jednym elementem i dlaczego zapętlać tę tablicę z jednym elementem, jeśli zawiera tylko jeden element? Po co rzucać liczby całkowite na obiekty w zewnętrznej pętli? Tutaj jest tyle pytań. Czy @CodeMadness to tylko konto trollowe?
Victor Zamanian

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

dostęp arrjak zwykle int[].


5
to nie odpowiada na pytanie, pytanie dotyczyło konwersji na typ pierwotny (int)
Asaf
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.