Автор оригинала: Eugen Paraschiv.
1. Обзор
В этом уроке я проиллюстрирую как разделить список на несколько подсписков заданного размера.
Для относительно простой операции в стандартных API-интерфейсах Java collection на удивление отсутствует поддержка. К счастью, и Guava , и Apache Commons Collections реализовали эту операцию аналогичным образом.
Эта статья является частью серии “Java – Back to Basic” здесь, на Baeldung.
Дальнейшее чтение:
Преобразование списка в строку в Java
Перетасовка Коллекций На Java
Введение в Spliterator на Java
2. Используйте Гуаву для разделения списка
Guava облегчает разбиение списка на подсписки заданного размера – с помощью операции Lists.partition :
@Test public void givenList_whenParitioningIntoNSublists_thenCorrect() { ListintList = 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:
@Test public void givenCollection_whenParitioningIntoNSublists_thenCorrect() { CollectionintCollection = 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)); }
Имейте в виду, что разделы являются представлениями подсписка исходной коллекции – это означает, что изменения в исходной коллекции будут отражены в разделах:
@Test public void givenListPartitioned_whenOriginalListIsModified_thenPartitionsChangeAsWell() { // Given ListintList = 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 недавно добавлена поддержка секционирования списка:
@Test public void givenList_whenParitioningIntoNSublists_thenCorrect() { ListintList = 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)); }
Нет соответствующей опции для разбиения необработанной коллекции – аналогично Guava Iterables.partition в коллекциях Commons.
Наконец, то же самое предостережение применимо и здесь – результирующие разделы являются представлениями исходного списка.
5. Используйте Java 8 для разделения списка
Теперь давайте посмотрим, как использовать Java 8 для разделения нашего списка.
5.1. Секционирование коллекторов
Мы можем использовать Collectors.partitioningBy() для разделения списка на 2 подсписка – следующим образом:
@Test public void givenList_whenParitioningIntoSublistsUsingPartitionBy_thenCorrect() { ListintList = 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. Группировка коллекторов
Мы также можем использовать Collectors.groupingBy() для разделения нашего списка на несколько разделов:
@Test public final void givenList_whenParitioningIntoNSublistsUsingGroupingBy_thenCorrect() { ListintList = 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. Разделите список разделителем
Мы также можем использовать Java 8 для разделения нашего списка разделителем:
@Test public void givenList_whenSplittingBySeparator_thenCorrect() { ListintList = 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. Оба они очень легкие и чрезвычайно полезные в целом, поэтому имеет смысл иметь один из них в пути к классу; однако, если это не вариант – здесь показано решение только для Java .
Реализация всех этих примеров и фрагментов кода может быть найдена на GitHub – это проект на основе Maven, поэтому его должно быть легко импортировать и запускать как есть.