Jak mogę wyciąć ArrayList z ArrayList w Javie?

80

Jak uzyskać wycinek tablicy ArrayListw języku Java? W szczególności chcę zrobić coś takiego:

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

Spodziewałem się więc, że to zadziała, ale Java zwraca List- więc jest niezgodny. A kiedy próbuję to przesłać, Java mi na to nie pozwala. Potrzebuję ArrayList- co mogę zrobić?

BT
źródło
4
Dlaczego nalegasz na używanie ArrayList? Myślę, że możesz nie rozumieć, jak działają interfejsy, ponieważ Listi ArrayListnie są „niekompatybilne” - ArrayListimplementują Listi Listprawdopodobnie zawierają wszystkie niezbędne metody, których potrzebujesz.
Bombe
2
Nalegam na używanie ArrayList, ponieważ jest to pytanie dotyczące podglądu ze sztywnym prototypem metody. Wyraźnie brakuje mi zrozumienia, ponieważ subList ma zwrócić typ listy, a mimo to nie mogę rzutować zwróconej listy na ArrayList. Więc powiedz mi stary ...
BT,
4
Jest całkowicie możliwe, że potrzebuje on, ArrayListponieważ następnie musi wywołać za jego pomocą metodę, która akceptuje rozszerzenie ArrayList. Prawdopodobnie taka metoda jest źle zaprojektowana i należy ją Listzamiast tego zaakceptować , ale takie sytuacje mogą pojawić się nie tylko w pytaniach podczas rozmowy kwalifikacyjnej, ale w kodzie napisanym przez innych, którego nie można po prostu przejść i zmienić. Współpracownicy i biblioteki nie zawsze są idealne.
Gravity

Odpowiedzi:

124

W Javie dobrą praktyką jest używanie typów interfejsów zamiast konkretnych klas w API.

Twoim problemem jest to, że używasz ArrayList(prawdopodobnie w wielu miejscach) miejsca, w którym naprawdę powinieneś używać List. W rezultacie stworzyłeś sobie problemy z niepotrzebnym ograniczeniem, że lista jest ArrayList.

Oto jak powinien wyglądać Twój kod:

List input = new ArrayList(...);

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

this.doSomething(input);

Twoje proponowane „rozwiązanie” problemu było następujące:

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

Działa to poprzez utworzenie kopii podlisty. To nie jest plasterek w normalnym sensie. Ponadto, jeśli podlista jest duża, wykonanie kopii będzie kosztowne.


Jeśli są ograniczane przez API, że nie można zmienić , tak że trzeba zadeklarować inputAjako ArrayList, może być w stanie realizować niestandardową podklasę ArrayList, w których subListmetoda zwraca podklasę ArrayList. Jednak:

  1. Zaprojektowanie, wdrożenie i przetestowanie wymagałoby dużo pracy.
  2. Dodałeś teraz znaczącą nową klasę do swojego kodu, prawdopodobnie z zależnościami od nieudokumentowanych aspektów (a zatem „podlegających zmianom”) aspektów ArrayListklasy.
  3. Musisz zmienić odpowiednie miejsca w bazie kodu, w których tworzysz ArrayListinstancje, aby zamiast tego tworzyć instancje swojej podklasy.

Rozwiązanie „kopiuj tablicę” jest bardziej praktyczne… biorąc pod uwagę, że nie są to prawdziwe wycinki.

Stephen C.
źródło
6
W rzeczywistości subList nie kopiuje; zwraca widok do oryginalnej listy ( docs.oracle.com/javase/6/docs/api/java/util/… )
Matt
3
Właściwie @Matthew, mam na myśli odpowiedź własną OP, w której robi to:new ArrayList(input.subList(0, input.size()/2))
Stephen C,
1
+1 dla tej frazy: w Javie dobrą praktyką jest używanie typów interfejsów zamiast konkretnych klas w API.
Ilonpilaaja
6

Znalazłem sposób, jeśli znasz startIndex i endIndex elementów, które należy usunąć z ArrayList

Pozwolić albyć przy ArrayList i startIndex, endIndexbyć początek i wskaźnik końca być usunięte z tablicy, odpowiednio:

al.subList(startIndex, endIndex + 1).clear();
Aman Gupta
źródło
6

Jeśli nie ma istniejącej metody, myślę, że możesz iterować od 0 do input.size()/2, biorąc każdy kolejny element i dołączając go do nowej ArrayList.

EDYCJA : Właściwie myślę, że możesz wziąć tę Listę i użyć jej do utworzenia wystąpienia nowej ArrayList przy użyciu jednego z konstruktorów ArrayList .

Jorge Israel Peña
źródło
2
Dokładnie to zrobiłem (zamieściłem moją odpowiedź, zanim przeczytałem twoją edycję). Dzięki
:)
Ale to kopiuje List, aby utworzyć nową ArrayList.
Joren
2
@BT - Dla przypomnienia, nie to zwykle oznacza termin „plasterek” w tym kontekście.
Stephen C
2

Chociaż ten post jest bardzo stary. Na wypadek, gdyby ktoś tego szukał ...

Guawa ułatwia podzielenie Listy na podlisty o określonym rozmiarze

List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
    List<List<Integer>> subSets = Lists.partition(intList, 3);
Hari Rao
źródło
Szybki link do dokumentacji Guava Lists: google.github.io/guava/releases/19.0/api/docs/com/google/common/ ...
AryanJ-NYC
-4

Tak to rozwiązałem. Zapomniałem, że podlista była bezpośrednim odniesieniem do elementów z oryginalnej listy, więc ma sens, dlaczego nie działa.

ArrayList<Integer> inputA = new ArrayList<Integer>(input.subList(0, input.size()/2));
BT
źródło