HOWTO · Java
Aufteilen einer Liste in Chunks in Java
Dieses Tutorial zeigt, wie Sie eine Liste in Java in mehrere gleich große Chunks aufteilen.
Auf dieser Seite
Um eine Java-Liste ohne zusätzliche Abhängigkeit in gleich große Blöcke aufzuteilen, durchlaufen Sie sie in Schritten der Blockgröße und entnehmen jeden Bereich mit List.subList(). Stream-Collector, Apache Commons Collections und Guava bieten Alternativen, wenn deren Ergebnisform oder eine bereits vorhandene Projektabhängigkeit zur Aufgabe passt.
Eine Liste in Java mit List.subList() in Blöcke aufteilen
List.subList(fromIndex, toIndex) gibt eine Ansicht eines Listenbereichs zurück: Der Anfang ist inklusive, das Ende exklusiv. Erhöhen Sie den Startindex jeweils um die Blockgröße und begrenzen Sie das Ende auf die Listenlänge, damit der letzte Block kürzer sein kann. Dieses vollständige Beispiel verwendet acht Werte und eine Blockgröße von drei. Die Bereiche der Schleife lassen sich anhand der Indizes direkt nachvollziehen.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ChunkExample {
public static void main(String[] args) {
List<Integer> items = Arrays.asList(10, 20, 30, 40, 50, 60, 70, 80);
int chunkSize = 3;
List<List<Integer>> chunks = new ArrayList<>();
for (int start = 0; start < items.size(); start += chunkSize) {
int end = Math.min(start + chunkSize, items.size());
chunks.add(items.subList(start, end));
}
System.out.println(chunks);
}
}
Die Startindizes sind 0, 3 und 6; der letzte Endindex wird auf die Listenlänge begrenzt. So bleibt jeder Wert erhalten, auch wenn der letzte Bereich kürzer ist. Bei einer leeren Eingabe fügt die Schleife keine Blöcke hinzu. Die Blockgröße muss positiv sein, damit die Schleife die Liste durchläuft.
Jedes Ergebnis von subList() bleibt an die ursprüngliche Liste gebunden und ist keine unabhängige Kopie. Behandeln Sie die Blöcke als Ansichten, wenn Änderungen auch in der Quellliste sichtbar sein sollen. Strukturelle Änderungen an der Quellliste außerhalb der Ansicht können dazu führen, dass sich ein Unterlistenbereich anschließend nicht mehr zuverlässig verwenden lässt. Um unabhängige Blocklisten zu erstellen, kopieren Sie beim Hinzufügen jeden Bereich, zum Beispiel mit new ArrayList<>(items.subList(start, end)).
Eine Liste in Java mit Java Streams in Blöcke aufteilen
Ein Stream kann Startindizes erzeugen und jeden Bereich auf eine Unterliste abbilden. Eine der vorgegebenen Varianten verwendet IntStream.iterate(0, i -> i < items.size(), i -> i + chunkSize), um Indizes zu erzeugen. Eine andere berechnet anhand der Listenlänge und der Blockgröße die Anzahl der Bereiche und bildet dann jeden Index i auf einen Bereich ab, der bei i * chunkSize beginnt. Beide Varianten erzeugen dieselben Bereiche wie die obige Schleife. Wenn Sie einen Stream-Ansatz wählen, gehören sie in diesen Abschnitt.
Bei beiden Varianten ist die Anzahl der Bereiche null, wenn die Eingabe keine Elemente enthält. Bevor Sie den letzten Index berechnen, muss die Blockgröße positiv sein. Für diese Stream-Varianten liegt kein Nachweis einer Ausführung auf einer Java-Laufzeit vor. Das Verhalten der Indizes wird daher anhand der APIs und der Berechnung beschrieben, nicht als getestetes Ergebnis. Die direkte Schleife lässt sich leichter anpassen, wenn die Grenzen an einer Stelle sichtbar sein sollen.
Eine Liste in Java mit Collectors.groupingBy() in Blöcke aufteilen
Collectors.groupingBy() gruppiert Stream-Elemente nach einem Klassifizierungsschlüssel. Um Blöcke zu bilden, ordnen Sie jedes Element anhand seiner Position geteilt durch die Blockgröße ein, nicht anhand seines Werts. Bei nullbasierten Positionen haben die Indizes von 0 bis chunkSize - 1 denselben Schlüssel; der folgende Bereich erhält den nächsten Schlüssel.
Zum Beispiel können Sie die Indizes streamen, sie mit Collectors.groupingBy(i -> i / chunkSize) gruppieren und anschließend jeden gruppierten Index wieder auf items.get(i) abbilden. Das Ergebnis ist eine Map, die Blocknummern auf Wertelisten abbildet. Wenn der Aufrufer eine Liste von Listen benötigt, sammeln Sie die Werte der Map in einer Liste. Verlassen Sie sich nicht auf die Iterationsreihenfolge der Map, sofern der gewählte Map-Typ und dessen Reihenfolge nicht Teil der Implementierung sind. Wie bei den anderen Ansätzen muss die Blockgröße positiv sein. Berücksichtigen Sie außerdem eine Eingabe ohne Elemente, bevor Sie die Anzahl der Bereiche berechnen.
Eine Liste in Java mit Apache Commons Collections in Blöcke aufteilen
Wenn Apache Commons Collections bereits eine Projektabhängigkeit ist, kann die Methode ListUtils.partition() eine Liste anhand der Liste und der Blockgröße als Argumente aufteilen: ListUtils.partition(items, chunkSize). Fügen Sie die Bibliothek zur Build-Konfiguration hinzu, bevor Sie diese API verwenden; sie gehört nicht zum JDK. Die Koordinaten der Abhängigkeit und API-Details finden Sie in der Version, die Ihr Projekt verwendet.
Hier sind weder eine Bibliotheksversion noch eine Abhängigkeits-Fixture oder ein Ausführungsnachweis angegeben. Der Artikel nennt daher die Methode, macht aber keine Zusagen dazu, ob die zurückgegebenen Partitionen Ansichten oder Kopien sind, ob sie veränderbar sind oder wie sich andere versionsabhängige Eigenschaften verhalten. Wenn diese Details wichtig sind, prüfen Sie die Dokumentation der konkreten Commons-Collections-Version in Ihrem Build.
Eine Liste in Java mit Google Guava in Blöcke aufteilen
Guava bietet die Methode Lists.partition(), die mit einer Liste und der Blockgröße aufgerufen wird: Lists.partition(items, chunkSize). Sie ist eine Option mit zusätzlicher Abhängigkeit, wenn Guava bereits in der Anwendung vorhanden ist. Andernfalls fügen Sie die Bibliothek über die Abhängigkeitsverwaltung des Projekts hinzu, bevor Sie die Collections-API importieren.
Hier sind weder eine Guava-Version noch eine ausführbare Abhängigkeits-Fixture angegeben. Die Methode wird daher nicht als getestetes Beispiel dargestellt. Prüfen Sie die API und jedes Verhalten, auf das Ihre Anwendung angewiesen ist, anhand der Guava-Version, die das Projekt verwendet. Allein der Methodenname begründet für eine bestimmte Version keine Zusagen zu Kopien, Ansichten, Veränderbarkeit oder Reihenfolge.
Fazit
Verwenden Sie die Indexschleife mit List.subList(), wenn eine Lösung ausschließlich mit dem JDK und eine explizite Behandlung der Bereiche zur Aufgabe passen. Wählen Sie eine Stream-Variante, wenn sich die indexbasierte Zuordnung in die vorhandene Pipeline einfügt, oder verwenden Sie Collectors.groupingBy(), wenn eine nach Blocknummern indizierte Map hilfreich ist. Apache Commons Collections und Guava bieten kompakte Bibliotheksalternativen, wenn diese Abhängigkeiten bereits zum Projekt gehören. Wählen Sie in jedem Fall eine positive Blockgröße, berücksichtigen Sie den letzten unvollständigen Block und prüfen Sie das Verhalten von Ansichten oder Sammlungen anhand der verwendeten API und Abhängigkeitsversion.