Как сделать вложенный список плоским в Java

В этой статье мы узнаем о вложенных коллекциях в Java и о том, как можно преобразовать их в плоские коллекции, используя различные подходы.

1. Что такое выравнивание?

В программировании, flatting a List означает объединение нескольких вложенных списков для создания одного списка. Flattened list состоит из всех элементов из вложенных списков.

List of nested lists: [[4, 5, 2], [1, 34, 23], [12], [10, 11, 15]];Flattened List: [4, 5, 2, 1, 34, 23, 12, 10, 11, 15];

В демонстрационных целях мы используем следующий вложенный список в каждом решении.

List<List<String>> nestedList = List.of(List.of("Alexandru", "John"),List.of("Emma","Andrew", "Luke"),List.of("Oliver"));

2. Использование пользовательской логики

Одно из самых простых решений — перебрать вложенные списки и добавить все элементы в новый объявленный плоский список. Мы можем добавить все элементы оптом с помощью функции addAll().

List<String> flatList = new ArrayList<>();nestedList.forEach(flatList::addAll);

Если исходный список также содержит отдельные элементы, то нам необходимо поставить условие if-else, чтобы сначала проверить тип элемента.

List<String> flatList = new ArrayList<>();for(Object item : nestedList) {if(item instanceof List<?>) {flatList.addAll(item)} else {flatList.add((String) item);}}

3. Использование потоков

API Java Streams предоставляет нам несколько интересных методов выравнивания вложенных связанных списков.

3.1 Использование flatMap()

Мы можем использовать функцию flatMap() с функцией mapper Collection::stream. При выполнении операции stream terminal каждый элемент flatMap() предоставляет отдельный поток. На заключительном этапе метод flatMap() преобразует все потоки в новый поток.

List<String> flatList = nestedList.stream().flatMap(Collection::stream).collect(Collectors.toList());

3.2 Использование reduce()

Редукция — это терминальный метод, агрегирующий поток. В методе reduce() мы передаем два аргумента функциям: первый называется identity, значение по умолчанию для редукции, а второй называется accumulator, который объединяет два значения.

В нашем случае, чтобы получить сглаженный List, нам нужно перебрать Stream и объединить последовательные списки в один для каждого последовательного вложенного List. Обратите внимание, что из-за дополнительных экземпляров ArrayList, созданных во время выполнения, этот метод не обеспечивает хорошей производительности для больших вложенных списков.

List<String> flatList = nestedList.stream().reduce(new ArrayList<>(),(l1, l2) -> {l1.addAll(l2);return l1;});

4. Использование коллекции Eclipse

Другой способ сделать список списков плоским — использовать метод flatCollect() из Eclipse Collections. Eclipse Collections — это фреймворк Java Collections, который имеет совместимые с JDK реализации List, Map и Set с богатым API.

Добавьте в приложение последнюю версию Eclipse Collection.

<dependency><groupId>org.eclipse.collections</groupId><artifactId>eclipse-collections</artifactId><version>11.1.0</version></dependency>

Мы будем использовать класс ListAdapter, который предоставляет обертку MutableList вокруг экземпляра интерфейса JDK Collections List и преобразует Java List в Eclipse Collection MutableList. После этого мы будем использовать его метод flatCollect(), который выровняет список списков.

 List<String> flatList = ListAdapter.adapt(nestedList).flatCollect(e -> e);

5. Использование гуавы

Добавьте последнюю версию Guava из репозитория Maven.

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.1-jre</version></dependency>

Метод Iterables.concat() отлично подходит для создания плоских списков из вложенных списков. Этот метод объединяет несколько итерируемых объектов в один итерируемый объект.

Iterable<String> iterable = Iterables.concat(nestedList);List<String> flatList = Lists.newArrayList(iterable);

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

Сглаживание вложенного списка может показаться сложным на первый взгляд, но это не так. Это можно легко сделать, используя только простую логику Java, потоки или даже внешние библиотеки коллекций.

Исходный код на Github

Прокрутить вверх