Як конвертувати ArrayList, що містить Integers, у примітивний масив Int?


297

Я намагаюся перетворити ArrayList, що містить об'єкти Integer, в примітивний int [] із наступним фрагментом коду, але він кидає помилку часу компіляції. Чи можливо конвертувати в Java?

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

10
Не точний дублікат цього питання (хоча і не дуже далеко)
Jonik

1
Так, це ArrayList, "дублікат" - це приблизно звичайний масив.
Скотт Макінтайр

3
Якщо вам не потрібні примітивні вставки, ви можете використовувати: List<Integer> x = new ArrayList<Integer>(); Integer[] n = x.toArray(new Integer[0]);
Evorlor

Відповіді:


219

Ви можете конвертувати, але я не думаю, що вбудовано щось, щоб зробити це автоматично:

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

(Зверніть увагу, що це викине NullPointerException, якщо будь-який integersабо будь-який елемент всередині нього є null.)

EDIT: Відповідно до коментарів, ви можете скористатися ітератором списку, щоб уникнути неприємних витрат зі списками, такими як 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
Можливо, краще повторити за допомогою ітератора списку (з кожним), щоб уникнути звернень до ефективності у списках, доступ яких не є O (1).
Меттью Вілліс

@Matthew: Так, можливо - буде редагувати, щоб надати це як альтернативу.
Джон Скіт

1
Ви також можете використовувати факт, що ArrayList реалізує Iterable (через спадщину колекції) і виконувати: for (int n: integer) {ret [counter ++] = n; } ... і ініціалізувати int counter = 0;
gardarh

8
набагато простіше зараз у Java8:integers.stream().mapToInt(Integer::valueOf).toArray
Manish Patel

241

Якщо ви використовуєте є й інший спосіб зробити це.

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

Що це робить:

  • отримання Stream<Integer>списку
  • отримання IntStreamшляхом зіставлення кожного елемента до себе (функція ідентичності), розблокування вмісту intзначення кожного Integerоб'єкта (робиться автоматично з Java 5)
  • отримання масиву int, зателефонувавшиtoArray

Ви також можете явно зателефонувати intValueза допомогою посилання на метод, тобто:

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

Варто також зазначити, що ви можете отримати ліцензію, NullPointerExceptionякщо у вас є будь-які nullпосилання в списку. Цього можна легко уникнути, додавши умову фільтрування до потокового трубопроводу таким чином:

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

Приклад:

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]

Я бачу, це можна використовувати для doubleтипів; чи немає еквіваленту для floatтипів?
code_dredd

Ви бачили перевагу Java 8, розробивши пояснення.
Євген

І саме тому Java 8+ Stream API прекрасний.
Пранов А.

67

Google Guava

Google Guava забезпечує акуратний спосіб зробити це, зателефонувавши Ints.toArray.

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

6
Я думаю, що це буде відповіддю для мене - я будь-який день займусь бібліотекою над функцією копіювання-вставки. Особливо бібліотекою, яку, можливо, пристойний розмір проекту вже використовує. Я сподіваюся, що ця відповідь в майбутньому отримає більше голосів та видимість.
Шон Конноллі

61

Apache Commons має клас ArrayUtils, який має метод toPrimitive (), який робить саме це.

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

Однак, як показав Джон, зробити це досить просто самостійно, а не використовувати зовнішні бібліотеки.


2
Зауважте, що цей підхід створить дві повні копії послідовності: один Integer [], створений toArray, і одна int [], створена всередині toPrimitive. Інша відповідь від Джона лише створює і заповнює один масив. Що потрібно враховувати, якщо у вас є великі списки, а ефективність важлива.
paraquat

Я вимірював продуктивність за допомогою ArrayUtils vs pure java та за невеликими списками (<25 елементів) чиста java більш ніж у 100 разів швидша. Для елементів 3k чиста Java все ще майже в 2 рази швидша ... (ArrayList <Integer> -> int [])
Оскар Лунд

@paraquat та Оскар Лунд насправді невірно. Так, наданий код створить два масиви, але такий підхід не робить. Проблема в цьому коді тут полягає у використанні масиву нульової довжини як аргументу. У ArrayList.toArray вихідний код показує , що якщо зміст буде відповідати, буде використовуватися вихідний масив. Я думаю, що в справедливому порівнянні ви знайдете цей метод настільки ж ефективним (якщо не більше) і, звичайно, менше кодом для підтримки.
Шон Конноллі


1
Яка мета нового цілого [0]?
Адам Х'юз

41

Я вважаю, що повторення за допомогою ітератора списку є кращою ідеєю, оскільки list.get(i)може мати низьку ефективність залежно від реалізації списку:

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

використання долара повинно бути досить простим:

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

Я планую вдосконалити DSL, щоб зняти проміжний toArray()виклик


1
Гей, просто хотів сказати, що раніше не бачив Долара, але я точно намагаюся спробувати наступний проект. Ось чудова маленька апі, яку ви туди ходите, продовжуйте гарну роботу :)
Барт Вандендріше

4

Це добре працює для мене :)

Знайдено на 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

Мене дивує, що ми заохочуємо одноразові користувацькі методи, коли цілком хороша, добре використана бібліотека, як Apache Commons, вже вирішила проблему. Хоча рішення є тривіальним, якщо не абсурдним, заохочувати таку поведінку через тривале технічне обслуговування та доступність, безвідповідально.

Просто зайдіть з Apache Commons


7
Я згоден з попереднім коментатором. Ви не тільки перетягуєте Apache Commons, але це легко перетворюється на великий набір перехідних залежностей, які також потрібно втягнути. Останнім часом я міг усунути дивовижну кількість залежностей, замінивши один рядок коду :-( Залежності дорогі і написання базового коду, як це є гарною практикою
Пітер Кріенс

1
Погоджено з @PeterKriens. Якщо що завгодно, в Java винна те, що не підтримують прості конверсії, як це у стандартних типах даних
Адам Хьюз

3

Якщо ви використовуєте Eclipse Collections , ви можете використовувати collectInt()метод для переходу з контейнера об'єктів у примітивний контейнер 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());

Якщо ви можете конвертувати ваш ArrayListфайл у FastList, ви можете позбутися адаптера.

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

Примітка. Я є прихильником колекцій Eclipse.



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

Вихід:

Масив примітивних вкладишів: [7, 9, 13]

Те саме працює для масиву longабо double, але не для масивів boolean,char , byte, shortабо float. Якщо у вас справді величезний список, є навіть такийparallelSetAll метод, який ви можете використовувати замість цього.

Для мене це досить добре і елегантно, що я не хотів би отримати зовнішню бібліотеку і не використовувати потоки для неї.

Посилання на документацію: Arrays.setAll(int[], IntUnaryOperator)


1

Ви можете просто скопіювати його в масив:

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

Не надто фантазії; але, ей, це працює ...


1

Дуже просте однолінійне рішення:

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

0

Цей сегмент коду працює для мене, спробуйте це:

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

Варто згадати ArrayList так, щоб це було оголошено так:

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

5
Привіт просто ніжне нагадування, що ОП хоче примітивний масив, а не об’єктний масив.
OLIVER.KOO

3
Первісний 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
Ця відповідь не працює, вона повертає масив з одним елементом замість кількох елементів.
Містичний

Навіщо використовувати StringBuffer? Навіщо перетворювати цілий рядок у рядок, а потім у цілий, а потім у цілий, а потім знову у цілий? Навіщо використовувати масив з одним елементом у ньому, і навіщо переходити на цей одноелементний масив, коли він містить лише один елемент? Навіщо кидати цілі особи до об'єктів у зовнішній цикл? Тут так багато питань. Чи @CodeMadness - лише обліковий запис тролів?
Віктор Заманян

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

доступ arrяк звичайний int[].


5
це не відповідає на питання, питання стосувалося переходу на примітивний тип (int)
Асаф
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.