Particionar uma lista em Java
1. Visão geral
Neste tutorial, ilustrareihow to split a List into several sublists de um determinado tamanho.
Para uma operação relativamente simples, surpreendentemente não há suporte nas APIs de coleta Java padrão. Felizmente,Guava eApache Commons Collections implementaram a operação de maneira semelhante.
Este artigo faz parte dethe “Java – Back to Basic” series aqui no exemplo.
Leitura adicional:
Convertendo uma lista em string em Java
Aprenda a converter uma lista em uma string usando diferentes técnicas.
Introdução ao Spliterator em Java
Aprenda sobre a interface do Spliterator que pode ser usada para percorrer e particionar seqüências.
2. Use Guava para particionar a lista
O Guava facilita o particionamento da Lista em sublistas de um tamanho especificado - viathe Lists.partition operation:
@Test
public void givenList_whenParitioningIntoNSublists_thenCorrect() {
List intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
List> subSets = Lists.partition(intList, 3);
List lastPartition = subSets.get(2);
List expectedLastPartition = Lists. newArrayList(7, 8);
assertThat(subSets.size(), equalTo(3));
assertThat(lastPartition, equalTo(expectedLastPartition));
}
3. Use Guava para particionar uma coleção
Partitioning a Collection também é possível com Goiaba:
@Test
public void givenCollection_whenParitioningIntoNSublists_thenCorrect() {
Collection intCollection = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
Iterable> subSets = Iterables.partition(intCollection, 3);
List firstPartition = subSets.iterator().next();
List expectedLastPartition = Lists. newArrayList(1, 2, 3);
assertThat(firstPartition, equalTo(expectedLastPartition));
}
Lembre-se de que as partições sãosublist views of the original collection - o que significa que as alterações na coleção original serão refletidas nas partições:
@Test
public void givenListPartitioned_whenOriginalListIsModified_thenPartitionsChangeAsWell() {
// Given
List intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
List> subSets = Lists.partition(intList, 3);
// When
intList.add(9);
// Then
List lastPartition = subSets.get(2);
List expectedLastPartition = Lists. newArrayList(7, 8, 9);
assertThat(lastPartition, equalTo(expectedLastPartition));
}
4. Use Apache Commons Collections para particionar a lista
Os lançamentos mais recentes do Apache Commons Collections também têm suporterecently added para particionar uma lista:
@Test
public void givenList_whenParitioningIntoNSublists_thenCorrect() {
List intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
List> subSets = ListUtils.partition(intList, 3);
List lastPartition = subSets.get(2);
List expectedLastPartition = Lists. newArrayList(7, 8);
assertThat(subSets.size(), equalTo(3));
assertThat(lastPartition, equalTo(expectedLastPartition));
}
Existeno corresponding option to partition a raw Collection - semelhante ao Guava Iterables.partition em Commons Collections.
Finalmente, a mesma ressalva se aplica aqui também - a partição resultante são vistas da Lista original.
5. Use Java8 para particionar a lista
Agora, vamos ver como usar o Java8 para particionar nossa lista.
5.1. ColetorespartitioningBy
Podemos usarCollectors.partitioningBy() para dividir a lista em 2 sublistas - da seguinte forma:
@Test
public void givenList_whenParitioningIntoSublistsUsingPartitionBy_thenCorrect() {
List intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
Map> groups =
intList.stream().collect(Collectors.partitioningBy(s -> s > 6));
List> subSets = new ArrayList>(groups.values());
List lastPartition = subSets.get(1);
List expectedLastPartition = Lists. newArrayList(7, 8);
assertThat(subSets.size(), equalTo(2));
assertThat(lastPartition, equalTo(expectedLastPartition));
}
Nota: As partições resultantes não são uma visualização da Lista principal, portanto, quaisquer alterações que ocorram na Lista principal não afetarão as partições.
5.2. ColetoresgroupingBy
Também podemos usarCollectors.groupingBy() para dividir nossa lista em várias partições:
@Test
public final void givenList_whenParitioningIntoNSublistsUsingGroupingBy_thenCorrect() {
List intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8);
Map> groups =
intList.stream().collect(Collectors.groupingBy(s -> (s - 1) / 3));
List> subSets = new ArrayList>(groups.values());
List lastPartition = subSets.get(2);
List expectedLastPartition = Lists. newArrayList(7, 8);
assertThat(subSets.size(), equalTo(3));
assertThat(lastPartition, equalTo(expectedLastPartition));
}
Nota: Assim comoCollectors.partitioningBy() - as partições resultantes não serão afetadas por mudanças na lista principal.
5.3. Divida a lista por separador
Também podemos usar o Java8 para dividir nossa lista por separador:
@Test
public void givenList_whenSplittingBySeparator_thenCorrect() {
List intList = Lists.newArrayList(1, 2, 3, 0, 4, 5, 6, 0, 7, 8);
int[] indexes =
Stream.of(IntStream.of(-1), IntStream.range(0, intList.size())
.filter(i -> intList.get(i) == 0), IntStream.of(intList.size()))
.flatMapToInt(s -> s).toArray();
List> subSets =
IntStream.range(0, indexes.length - 1)
.mapToObj(i -> intList.subList(indexes[i] + 1, indexes[i + 1]))
.collect(Collectors.toList());
List lastPartition = subSets.get(2);
List expectedLastPartition = Lists. newArrayList(7, 8);
assertThat(subSets.size(), equalTo(3));
assertThat(lastPartition, equalTo(expectedLastPartition));
}
Nota: Usamos “0” como separador - primeiro obtivemos os índices de todos os elementos “0” na Lista, depois dividimos oList nesses índices.
6. Conclusão
As soluções apresentadas aqui fazem uso de bibliotecas adicionais - Guava ou a biblioteca Apache Commons Collections. Ambos são muito leves e extremamente úteis em geral, portanto, faz todo o sentido ter um deles no caminho de classe; no entanto, se isso não for uma opção - uma solução Java apenasis shown here.
A implementação de todos esses exemplos e trechos de códigocan be found over on GitHub– este é um projeto baseado em Maven, portanto, deve ser fácil de importar e executar como está.