Wie kann ich eine ArrayList aus einer ArrayList in Java herausschneiden?

80

Wie bekomme ich ein Array-Slice von ArrayListin Java? Konkret möchte ich so etwas machen:

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

Ich habe erwartet, dass dies funktioniert, aber Java gibt a zurück List- es ist also nicht kompatibel. Und wenn ich versuche, es zu besetzen, lässt mich Java nicht. Ich brauche ein ArrayList- was kann ich tun?

BT
quelle
4
Warum bestehen Sie darauf, eine zu verwenden ArrayList? Ich denke , man kann ein wenig Verständnis fehlt , wie Schnittstellen arbeiten , weil Listund ArrayListnicht „unvereinbar“ - ArrayListGeräte List, und Listwahrscheinlich enthält alle notwendigen Methoden , die Sie benötigen.
Bombe
2
Ich bestehe darauf, ArrayList zu verwenden, da es sich um eine Interviewfrage mit einem starren Methodenprototyp handelt. Ich habe eindeutig ein Unverständnis, weil subList einen Listentyp zurückgeben soll, und dennoch kann ich die zurückgegebene Liste nicht in ArrayList umwandeln. Also sagst du mir Mann ..
BT
4
Es ist durchaus möglich, dass er eine benötigt, ArrayListweil er dann eine Methode damit aufrufen muss, die eine akzeptiert ArrayList. Wahrscheinlich ist eine solche Methode schlecht konzipiert und sollte Liststattdessen akzeptiert werden, aber solche Situationen können nicht nur in Interviewfragen auftreten, sondern auch in Code, der von anderen geschrieben wurde und den man nicht einfach ändern kann. Mitarbeiter und Bibliotheken sind nicht immer perfekt.
Schwerkraft

Antworten:

124

In Java empfiehlt es sich, in APIs eher Schnittstellentypen als konkrete Klassen zu verwenden.

Ihr Problem ist, dass Sie ArrayList(wahrscheinlich an vielen Orten) verwenden, wo Sie wirklich verwenden sollten List. Infolgedessen haben Sie Probleme mit einer unnötigen Einschränkung erstellt, dass die Liste eine ist ArrayList.

So sollte Ihr Code aussehen:

List input = new ArrayList(...);

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

this.doSomething(input);

Ihre vorgeschlagene "Lösung" für das Problem war / ist:

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

Das funktioniert, indem eine Kopie der Unterliste erstellt wird. Es ist keine Scheibe im normalen Sinne. Wenn die Unterliste groß ist, ist das Erstellen der Kopie außerdem teuer.


Wenn Sie durch APIs eingeschränkt sind , dass Sie nicht ändern können , so dass Sie zu haben , zu erklären , inputAwie ein ArrayList, können Sie möglicherweise eine benutzerdefinierte Unterklasse von implementieren , ArrayListin dem das subListVerfahren eine Unterklasse von zurückgibt ArrayList. Jedoch:

  1. Das Entwerfen, Implementieren und Testen wäre viel Arbeit.
  2. Sie haben Ihrer Codebasis jetzt eine bedeutende neue Klasse hinzugefügt, möglicherweise mit Abhängigkeiten von undokumentierten Aspekten (und daher "Änderungen vorbehalten") der ArrayListKlasse.
  3. Sie müssten relevante Stellen in Ihrer Codebasis ändern, an denen Sie ArrayListInstanzen erstellen, um stattdessen Instanzen Ihrer Unterklasse zu erstellen.

Die Lösung "Copy the Array" ist praktischer ... wenn man bedenkt, dass dies keine echten Slices sind.

Stephen C.
quelle
6
Tatsächlich erstellt subList keine Kopie. es gibt eine Ansicht in die ursprüngliche Liste zurück ( docs.oracle.com/javase/6/docs/api/java/util/… )
Matt
3
Eigentlich @Matthew, ich beziehe mich auf die Selbstantwort des OP, wo er dies tut:new ArrayList(input.subList(0, input.size()/2))
Stephen C
1
+1 für diesen Satz: In Java empfiehlt es sich, in APIs eher Schnittstellentypen als konkrete Klassen zu verwenden.
Ilonpilaaja
6

Ich habe einen Weg gefunden, wenn Sie startIndex und endIndex der Elemente kennen, die aus ArrayList entfernt werden müssen

Lassen Sie alwerden das Original und Arraylist startIndex, endIndexwerden Start- und End - Index jeweils aus dem Array entfernt werden:

al.subList(startIndex, endIndex + 1).clear();
Aman Gupta
quelle
6

Wenn es keine Methode gibt, können Sie von 0 bis iterieren input.size()/2, indem Sie jedes aufeinanderfolgende Element nehmen und an eine neue ArrayList anhängen.

EDIT : Eigentlich denke ich, dass Sie diese Liste verwenden können, um eine neue ArrayList mit einem der ArrayList-Konstruktoren zu instanziieren .

Jorge Israel Peña
quelle
2
Genau das habe ich getan (habe meine Antwort gepostet, bevor ich Ihre Bearbeitung gelesen habe). Danke
BT
Dass aber die Kopien der Liste , um eine neue Arraylist zu machen.
Joren
2
@BT - Für den Datensatz ist dies nicht das, was der Begriff "Slice" in diesem Zusammenhang normalerweise bedeutet.
Stephen C
2

Obwohl dieser Beitrag sehr alt ist. Für den Fall, dass jemand danach sucht ..

Guava erleichtert die Aufteilung der Liste in Unterlisten einer bestimmten Größe

List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
    List<List<Integer>> subSets = Lists.partition(intList, 3);
Hari Rao
quelle
Schneller Link zur Dokumentation der Guavenlisten
AryanJ-NYC
-4

So habe ich es gelöst. Ich habe vergessen, dass die Unterliste ein direkter Verweis auf die Elemente in der ursprünglichen Liste ist, daher ist es sinnvoll, warum es nicht funktioniert.

ArrayList<Integer> inputA = new ArrayList<Integer>(input.subList(0, input.size()/2));
BT
quelle