Як я можу вирізати ArrayList із ArrayList у Java?


80

Як отримати фрагмент масиву ArrayListв Java? Зокрема, я хочу зробити щось подібне:

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

Тож я очікував, що це спрацює, але Java повертає a List- отже, це несумісно. І коли я намагаюся його кинути, Java не дозволяє мені. Мені потрібно ArrayList- що я можу зробити?


4
Чому ви наполягаєте на використанні ArrayList? Я думаю , що ви , можливо , чи не вистачає трохи розуміння того, як інтерфейси працюють , тому що Listі ArrayListне є «несумісними» - ArrayListзнаряддя List, і , Listймовірно , містить всі необхідні методи вам потрібно.
Bombe

2
Я наполягаю на використанні ArrayList, оскільки це питання про інтев'ю з жорстким прототипом методу. У мене явно недостатньо розуміння, оскільки subList повинен повертати тип Списку, і все ж я не можу передати повернутий Список в ArrayList. Тож ти скажи мені, чоловіче ..
BT

4
Цілком можливо, що йому потрібен ArrayListфайл, оскільки йому тоді потрібно викликати метод, який приймає ArrayList. Можливо, такий метод погано розроблений і його слід приймати Listнатомість, але такі ситуації можуть виникати не тільки під час запитань на співбесіду, але і в коді, написаному іншими, що не можна просто піти і змінитись. Співробітники та бібліотеки не завжди ідеальні.
Гравітація

Відповіді:


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, я маю на увазі самовідповідь OP, де він робить це:new ArrayList(input.subList(0, input.size()/2))
Стівен С.

1
+1 для цієї фрази: У Java корисно використовувати типи інтерфейсів, а не конкретні класи в API.
Ілонпілаая,

6

Я знайшов спосіб, якщо ви знаєте startIndex та endIndex елементів, які потрібно видалити з ArrayList

Нехай alбуде оригінальним ArrayList і startIndex,endIndex бути початковим та кінцевим індексами, які слід видалити з масиву відповідно:

al.subList(startIndex, endIndex + 1).clear();

6

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

EDIT : Насправді, я думаю, ви можете взяти цей Список і використати його для створення нового ArrayList за допомогою одного з конструкторів ArrayList .


2
Це саме те, що я зробив (розмістив свою відповідь, перш ніж прочитати вашу редакцію). Дякую
:)

Але це копіює Список, щоб створити новий ArrayList.
Йорен

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

Швидке посилання на документацію щодо списків Гуави
AryanJ-NYC

-4

Ось як я це вирішив. Я забув, що підсписок був прямим посиланням на елементи у вихідному списку, тому має сенс, чому він не буде працювати.

ArrayList<Integer> inputA = new ArrayList<Integer>(input.subList(0, input.size()/2));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.