Разделить список в Java

Разделение списка в Java

1. обзор

В этом уроке я проиллюстрируюhow to split a List into several sublists заданного размера.

Для относительно простой операции неожиданно нет поддержки в стандартных API коллекции Java. К счастью, какGuava, так иApache Commons Collections реализовали операцию аналогичным образом.

Эта статья является частьюthe “Java – Back to Basic” series здесь для примера.

Дальнейшее чтение:

Преобразование списка в строку в Java

Узнайте, как преобразовать список в строку, используя различные методы.

Read more

Перестановки коллекций на Java

Узнайте, как перемешать различные коллекции в Java.

Read more

Введение в Spliterator в Java

Узнайте об интерфейсе Spliterator, который можно использовать для обхода и разбиения последовательностей.

Read more

2. Используйте Guava для разделения списка

Guava упрощает разделение списка на подсписки указанного размера - черезthe 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. Используйте Guava для разделения коллекции

Partitioning a Collection также возможно с 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));
}

Имейте в виду, что это разделыsublist views of the original collection - это означает, что изменения в исходной коллекции будут отражены в разделах:

@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. Используйте коллекции Apache Commons для разделения списка

В последних выпусках коллекций Apache Commons есть поддержкаrecently added для разделения списка:

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

Естьno corresponding option to partition a raw Collection - аналогично разделу Guava Iterables. в коллекциях Commons.

Наконец, то же самое относится и к этому предупреждению - получившийся раздел является видом исходного списка.

5. Используйте Java8 для разделения списка

Теперь давайте посмотрим, как использовать Java8 для разделения нашего списка.

5.1. КоллекторыpartitioningBy

Мы можем использоватьCollectors.partitioningBy(), чтобы разделить список на 2 подсписка - следующим образом:

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

Примечание. Полученные разделы не являются видом основного списка, поэтому любые изменения, внесенные в основной список, не повлияют на разделы.

5.2. КоллекторыgroupingBy

Мы также можем использоватьCollectors.groupingBy(), чтобы разделить наш список на несколько разделов:

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

Примечание. Как иCollectors.partitioningBy() - полученные разделы не будут затронуты изменениями в основном списке.

5.3. Разделить список по разделителю

Мы также можем использовать Java8 для разделения нашего списка по разделителю:

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

Примечание. Мы использовали «0» в качестве разделителя - сначала мы получили индексы всех элементов «0» в списке, затем мы разбилиList на эти индексы.

6. Заключение

Решения, представленные здесь, используют дополнительные библиотеки - Guava или библиотеку Apache Commons Collections. Оба они очень легкие и чрезвычайно полезные в целом, поэтому имеет смысл иметь один из них в пути к классам; однако, если это не вариант - решение только для Javais shown here.

Реализация всех этих примеров и фрагментов кодаcan be found over on GitHub - это проект на основе Maven, поэтому его должно быть легко импортировать и запускать как есть.