Divida una lista en sublistas de tamaño `n` en Java
Esta publicación discutirá cómo dividir una lista en sublistas de tamaño n
en Java. Tenga en cuenta que la lista final puede ser más pequeña que n
dependiendo del tamaño de la lista.
1. Usar Guava
Con la biblioteca Guava, puede usar el Lists.partition() para dividir una lista en sublistas consecutivas, cada una del tamaño especificado. El siguiente es un ejemplo simple que demuestra el uso de este método:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import com.google.common.collect.Lists; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; class Main { public static void main(String[] args) { List<Integer> collection = IntStream.rangeClosed(1, 15) .boxed().collect(Collectors.toList()); int partitionSize = 4; List<List<Integer>> partition = Lists.partition(collection, partitionSize); System.out.println(partition); } } |
Resultado:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]]
2. Uso de las colecciones de Apache Commons
Similar a la de Guava Lists.partition()
método, Colecciones de Apache Commons ListUtils
ofertas de clases partition()
método que ofrece una funcionalidad similar.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import org.apache.commons.collections4.ListUtils; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; class Main { public static void main(String[] args) { List<Integer> collection = IntStream.rangeClosed(1, 15) .boxed().collect(Collectors.toList()); int partitionSize = 4; List<List<Integer>> partitions = ListUtils.partition(collection, partitionSize); System.out.println(partitions); } } |
Resultado:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]]
3. Usando List.subList()
método
Si no prefiere bibliotecas de terceros, puede escribir su propia rutina para esta tarea. Las siguientes soluciones utilizan un ciclo for regular para iterar la lista y el List.subList()
método para obtener la partición entre el índice inicial y el final.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; class Main { public static void main(String[] args) { List<Integer> collection = IntStream.rangeClosed(1, 15) .boxed().collect(Collectors.toList()); int partitionSize = 4; List<List<Integer>> partitions = new ArrayList<>(); for (int i = 0; i < collection.size(); i += partitionSize) { partitions.add(collection.subList(i, Math.min(i + partitionSize, collection.size()))); } System.out.println(partitions); } } |
Resultado:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]]
Esto es equivalente a lo siguiente usando Java 8 Stream API:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; class Main { private static <T> List<List<T>> partition(List<T> collection, int partitionSize) { return IntStream.rangeClosed(0, (collection.size() - 1) / partitionSize) .mapToObj(i -> collection.subList(i * partitionSize, Math.min((i + 1) * partitionSize, collection.size()))) .collect(Collectors.toList()); } public static void main(String[] args) { List<Integer> collection = IntStream.rangeClosed(1, 15) .boxed().collect(Collectors.toList()); int partitionSize = 4; List<List<Integer>> partitions = partition(collection, partitionSize); System.out.println(partitions); } } |
Resultado:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]]
Finalmente, con Java 9 puedes simplificar el código usando el IntStream.iterate()
método que toma un predicado.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; class Main { private static <T> List<List<T>> partition(List<T> collection, int partitionSize) { return IntStream.iterate(0, i -> i < collection.size(), i -> i + partitionSize) .mapToObj(i -> collection.subList(i, Math.min(i + partitionSize, collection.size()))) .collect(Collectors.toList()); } public static void main(String[] args) { List<Integer> collection = IntStream.rangeClosed(1, 15) .boxed().collect(Collectors.toList()); int partitionSize = 4; List<List<Integer>> partitions = partition(collection, partitionSize); System.out.println(partitions); } } |
Resultado:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]]
4. Uso Collectors.groupingBy()
método
Hay más formas de dividir una lista en Java utilizando Stream API. La siguiente solución utiliza Collectors.groupingBy()
para realizar el equivalente de una operación de "agrupar por" en los elementos de la lista. Agrupa los elementos según una función de clasificación y devuelve los resultados en un mapa.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import java.util.Collection; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; class Main { private static <T> Collection<List<T>> partition(List<T> collection, int n) { return IntStream.range(0, collection.size()).boxed() .collect(Collectors.groupingBy(i -> i / n, Collectors.mapping(collection::get, Collectors.toList()))) .values(); } public static void main(String[] args) { List<Integer> collection = IntStream.rangeClosed(1, 15) .boxed().collect(Collectors.toList()); int partitionSize = 4; Collection<List<Integer>> partitions = partition(collection, partitionSize); System.out.println(partitions); } } |
Resultado:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]]
El código se puede simplificar usando un contador mutable como AtomicInteger
clase:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.IntStream; class Main { private static <T> Collection<List<T>> partition(List<T> collection, int n) { AtomicInteger counter = new AtomicInteger(); return collection.stream() .collect(Collectors.groupingBy(it -> counter.getAndIncrement() / n)) .values(); } public static void main(String[] args) { List<Integer> collection = IntStream.rangeClosed(1, 15) .boxed().collect(Collectors.toList()); int partitionSize = 4; Collection<List<Integer>> partitions = partition(collection, partitionSize); System.out.println(partitions); } } |
Resultado:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15]]
Se trata de dividir una lista en sublistas de tamaño n
en Java.