Как я могу вырезать ArrayList из ArrayList в Java?

80

Как получить фрагмент массива ArrayListв Java? В частности, я хочу сделать что-то вроде этого:

ArrayList<Integer> inputA = input.subList(0, input.size()/2);
// where 'input' is a prepouplated ArrayList<Integer>

Итак, я ожидал, что это сработает, но Java возвращает List- так что это несовместимо. И когда я пытаюсь его закинуть, Java не позволяет. Мне нужен ArrayList- что я могу сделать?

BT
источник
4
Почему вы настаиваете на использовании ArrayList? Я думаю , что вы , возможно , не хватает немного понимания того, как интерфейсы работают , потому что Listи ArrayListне являются «несовместимыми» - ArrayListорудия List, и , Listвероятно , содержит все необходимые методы вам нужно.
Bombe
2
Я настаиваю на использовании ArrayList, потому что это вопрос интервью с жестким прототипом метода. Я явно не понимаю, потому что subList должен возвращать тип List, но я не могу преобразовать возвращенный List в ArrayList. Так ты говоришь мне, чувак ..
BT
4
Вполне возможно, что ему нужен объект, ArrayListпотому что затем ему нужно вызвать с ним метод, который принимает ArrayList. Возможно, такой метод плохо спроектирован и должен быть принят Listвместо него, но такие ситуации могут возникать не только в вопросах интервью, но и в коде, написанном другими, который нельзя просто пойти и изменить. Коллеги и библиотеки не всегда идеальны.
Gravity

Ответы:

124

В Java рекомендуется использовать типы интерфейсов, а не конкретные классы в API.

Ваша проблема в том, что вы используете ArrayList(вероятно, во многих местах) там, где вам действительно стоит использовать List. В результате вы создали себе проблемы из-за ненужного ограничения, что список является расширением ArrayList.

Вот как должен выглядеть ваш код:

List input = new ArrayList(...);

public void doSomething(List input) {
   List inputA = input.subList(0, input.size()/2);
   ...
}

this.doSomething(input);

Предлагаемое вами «решение» проблемы было следующим:

new ArrayList(input.subList(0, input.size()/2))

Это работает путем создания копии подсписка. Это не кусок в обычном понимании. Кроме того, если подсписок большой, создание копии будет дорогостоящим.


Если вы ограничены API-интерфейсами, которые вы не можете изменить , например, которые вы должны объявить inputAкак объект ArrayList, вы можете реализовать собственный подкласс, ArrayListв котором subListметод возвращает подкласс ArrayList. Тем не мение:

  1. Было бы много работы по разработке, внедрению и тестированию.
  2. Теперь вы добавили значительный новый класс в свою базу кода, возможно, с зависимостями от недокументированных аспектов (и, следовательно, «подлежащих изменению») аспектов ArrayList класса.
  3. Вам нужно будет изменить соответствующие места в вашей кодовой базе, где вы создаете ArrayListэкземпляры, чтобы вместо этого создать экземпляры вашего подкласса.

Решение «скопировать массив» более практично ... учитывая, что это не настоящие срезы.

Стивен С
источник
6
На самом деле subList не копирует; он возвращает представление в исходный список ( docs.oracle.com/javase/6/docs/api/java/util/… )
Мэтт
3
На самом деле @Matthew, я имею в виду самостоятельный ответ ОП, где он делает это:new ArrayList(input.subList(0, input.size()/2))
Стивен С.
1
+1 за эту фразу: в Java рекомендуется использовать типы интерфейса, а не конкретные классы в API.
Ilonpilaaja
6

Я нашел способ, если вы знаете startIndex и endIndex элементов, которые нужно удалить из ArrayList

Позвольте alбыть исходным ArrayList и startIndex, endIndexбыть начальным и конечным индексами, которые будут удалены из массива соответственно:

al.subList(startIndex, endIndex + 1).clear();
Аман Гупта
источник
6

Если нет существующего метода, я думаю, вы можете выполнить итерацию от 0 до input.size()/2, беря каждый последовательный элемент и добавляя его в новый список ArrayList.

РЕДАКТИРОВАТЬ : На самом деле, я думаю, вы можете взять этот список и использовать его для создания экземпляра нового ArrayList с помощью одного из конструкторов ArrayList .

Хорхе Исраэль Пенья
источник
2
Это именно то, что я сделал (опубликовал свой ответ до того, как прочитал ваше изменение). Спасибо
:)
Но это копирует список, чтобы создать новый ArrayList.
Joren
2
@BT - Для справки, термин «срез» обычно означает в данном контексте не это.
Stephen C
2

Хотя этот пост очень старый. На случай, если кто-то это ищет ..

Guava упрощает разделение списка на подсписки указанного размера.

List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
    List<List<Integer>> subSets = Lists.partition(intList, 3);
Хари Рао
источник
Быстрая ссылка на документацию по спискам Guava: google.github.io/guava/releases/19.0/api/docs/com/google/common/…
AryanJ-NYC
-4

Вот как я это решил. Я забыл, что подсписок был прямой ссылкой на элементы в исходном списке, поэтому понятно, почему это не сработало.

ArrayList<Integer> inputA = new ArrayList<Integer>(input.subList(0, input.size()/2));
BT
источник