Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Как превратить список списков в один список

Короткий ответ

flatMap() заменяет каждый элемент потоком и склеивает эти потоки в один:

void main() {
    List<List<Integer>> nested = List.of(List.of(1, 2), List.of(3), List.of(4, 5, 6));
    List<Integer> flat = nested.stream().flatMap(List::stream).toList();
 
    IO.println(flat);
}

Результат:

[1, 2, 3, 4, 5, 6]

Вложенное поле

Часто список лежит внутри объекта — например, товары внутри заказов:

record Order(int id, List<String> products) {}
 
void main() {
    var orders = List.of(new Order(1, List.of("tea", "cake")), new Order(2, List.of("coffee", "tea")));
 
    var allProducts = orders.stream().flatMap(o -> o.products().stream()).distinct().toList();
    IO.println(allProducts);
}

Результат:

[tea, cake, coffee]

Массивы

Для массива массивов используйте Arrays::stream:

void main() {
    String[][] table = {{"a", "b"}, {"c"}};
    IO.println(Arrays.stream(table).flatMap(Arrays::stream).toList());
}

Результат:

[a, b, c]

Слова из строк

flatMap() удобен, чтобы разбить строки на слова и собрать их вместе:

void main() {
    var lines = List.of("to be", "or not to be");
    var words = lines.stream().flatMap(line -> Arrays.stream(line.split(" "))).toList();
 
    IO.println(words);
}

Результат:

[to, be, or, not, to, be]

Частая ошибка

Использовать map() вместо flatMap(). Получается поток потоков, а не поток элементов:

void main() {
    List<List<Integer>> nested = List.of(List.of(1, 2), List.of(3));
    IO.println(nested.stream().map(List::stream).toList());
}

Результат:

[java.util.stream.ReferencePipeline$Head@2c34f934, java.util.stream.ReferencePipeline$Head@12d3a4e9]

Адреса объектов после @ у вас будут другими.

Функции из этого ответа

  • Stream.flatMap() — Превращает каждый элемент в поток и склеивает все потоки в один.
  • Stream.toList() — Собирает элементы потока в неизменяемый список.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.