Partizionare un elenco in Java

1. Panoramica

In questo tutorial illustrerò come dividere un elenco in più sottoliste di una data dimensione.

Per un'operazione relativamente semplice, sorprendentemente non c'è supporto nelle API di raccolta Java standard. Fortunatamente, sia Guava che le collezioni Apache Commons hanno implementato l'operazione in modo simile.

Questo articolo fa parte della serie " Java - Back to Basic " qui su Baeldung.

2. Utilizzare Guava per partizionare l'elenco

Guava facilita il partizionamento dell'elenco in sottoliste di una dimensione specificata, tramite l' operazione Lists.partition :

@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. Utilizzare Guava per partizionare una raccolta

Il partizionamento di una raccolta è possibile anche con Guava:

@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)); }
    

Tieni presente che le partizioni sono visualizzazioni di elenchi secondari della raccolta originale , il che significa che le modifiche nella raccolta originale si rifletteranno nelle partizioni:

@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. Utilizzare le collezioni Apache Commons per partizionare l'elenco

Le ultime versioni di Apache Commons Collections hanno recentemente aggiunto il supporto anche per il partizionamento di un elenco:

@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)); }
    

Non esiste un'opzione corrispondente per partizionare una raccolta non elaborata, simile a Guava Iterables.partition in Commons Collections.

Infine, lo stesso avvertimento si applica anche qui: le partizioni risultanti sono viste dell'elenco originale.

5. Utilizzare Java8 per partizionare l'elenco

Vediamo ora come utilizzare Java8 per partizionare la nostra lista.

5.1. Partizionamento dei collezionisti

Possiamo usare Collectors.partitioningBy () per dividere l'elenco in 2 sottoliste - come segue:

@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: le partizioni risultanti non sono una vista dell'elenco principale, quindi qualsiasi modifica apportata all'elenco principale non influirà sulle partizioni.

5.2. Raggruppamento di collezionisti

Possiamo anche usare Collectors.groupingBy () per dividere il nostro elenco in più partizioni:

@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: proprio come Collectors.partitioningBy () , le partizioni risultanti non saranno influenzate dalle modifiche nella lista principale.

5.3. Dividi l'elenco per separatore

Possiamo anche usare Java8 per dividere la nostra lista per separatore:

@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: abbiamo utilizzato "0" come separatore: prima abbiamo ottenuto gli indici di tutti gli elementi "0" nell'elenco, quindi abbiamo suddiviso l' elenco su questi indici.

6. Conclusione

Le soluzioni presentate qui fanno uso di librerie aggiuntive: Guava o la libreria Apache Commons Collections. Entrambi sono molto leggeri ed estremamente utili nel complesso, quindi ha perfettamente senso averne uno sul percorso di classe; tuttavia, se questa non è un'opzione, qui viene mostrata una soluzione solo Java.

L'implementazione di tutti questi esempi e frammenti di codice può essere trovata su GitHub : questo è un progetto basato su Maven, quindi dovrebbe essere facile da importare ed eseguire così com'è.