Как преобразовать ArrayList, содержащий целые числа, в примитивный массив int?

297

Я пытаюсь преобразовать ArrayList, содержащий объекты Integer, в примитив int [] со следующим фрагментом кода, но он выдает ошибку времени компиляции. Можно ли конвертировать в Java?

List<Integer> x =  new ArrayList<Integer>();
int[] n = (int[])x.toArray(int[x.size()]);
Snehal
источник
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.)

РЕДАКТИРОВАТЬ: Согласно комментариям, вы можете использовать итератор списка, чтобы избежать неприятных затрат со списками, такими как 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).
Мэтью Уиллис
@ Матфея: Да, возможно - будет редактировать, чтобы дать это в качестве альтернативы.
Джон Скит
1
Вы также можете использовать тот факт, что ArrayList реализует Iterable (через наследование Collection) и do: for (int n: integer) {ret [counter ++] = n; } ... и инициализировать int counter = 0;
gardarh
8
теперь намного проще в Java8:integers.stream().mapToInt(Integer::valueOf).toArray
Маниш Патель
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);
Snehal
источник
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. Другой ответ от Джона создает и заполняет только один массив. Что-то, чтобы рассмотреть, если у вас есть большие списки, и производительность важна.
паракват
Я измерил производительность, используя ArrayUtils против чистой Java, и в небольших списках (<25 элементов) чистая Java работает более чем в 100 раз. Для элементов 3k чистый java по-прежнему почти в 2 раза быстрее ... (ArrayList <Integer> -> int [])
Оскар Лунд,
@paraquat & Оскар Лунд, это не совсем правильно. Да, предоставленный код создаст два массива, но этот подход - нет. Проблема в этом коде здесь заключается в использовании массива нулевой длины в качестве аргумента. В ArrayList.toArray исходный код показывает , что если содержание будет соответствовать, будет использоваться исходный массив. Я думаю, что в честном сравнении вы найдете этот метод настолько же эффективным (если не больше) и, конечно, меньше кода для поддержки.
Шон Коннолли
PS: хороший связанный пост
Шон Коннолли
1
Какова цель нового Integer [0]?
Адам Хьюз
41

Я считаю, что итерация с использованием итератора List является лучшей идеей, поскольку list.get(i)может иметь низкую производительность в зависимости от реализации List:

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

Использование Dollar должно быть довольно простым:

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

Я планирую улучшить DSL, чтобы удалить промежуточный toArray()вызов

DFA
источник
1
Эй, просто хотел сказать, что я раньше не видел Dollar, но я определенно пробую свой следующий проект. Это отличный маленький API, у вас есть там, продолжайте в том же духе :)
Барт Vandendriessche
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));
    }
}
angelhernandez
источник
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.

Крейг П. Мотлин
источник
3

Java 8:

int[] intArr = Arrays.stream(integerList).mapToInt(i->i).toArray();
EssaidiM
источник
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);
}

Не слишком причудливый; но, эй, это работает ...

sagiksp
источник
1

Очень простое однострочное решение:

Integer[] i = arrlist.stream().toArray(Integer[]::new);
PramodG
источник
0

Этот сегмент кода работает для меня, попробуйте это:

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

Стоит отметить, что ArrayList должен быть объявлен так:

ArrayList<Integer> list = new ArrayList<>();
user3444748
источник
5
Здравствуйте, просто мягкое напоминание, что OP хочет массив примитивов, а не массив объектов.
OLIVER.KOO
3
Примитив int, а не обертка Integer!
Барцилла
-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());
    }
CodeMadness
источник
1
Этот ответ не работает, он возвращает массив с одним элементом вместо нескольких элементов.
Мистик
Зачем использовать StringBuffer? Зачем преобразовывать целое число в строку, а затем в целое число, а затем в целое число, а затем снова в целое число? Зачем использовать массив с единственным элементом в нем, и зачем зацикливаться на этом одноэлементном массиве, когда он содержит только один элемент? Зачем приводить целые числа к объектам во внешнем цикле? Здесь так много вопросов. Является ли @CodeMadness тролль-аккаунтом?
Виктор Заманян
-5
Integer[] arr = (Integer[]) x.toArray(new Integer[x.size()]);

доступ arrвроде нормальный int[].

ПНЧ
источник
5
это не отвечает на вопрос, вопрос был о преобразовании в примитивный тип (int)
Asaf