Java - flatMap, map

stream과 친해지기

Posted by Yan on December 17, 2021

flatMap()과 map()의 차이

mozilla에 의하면, Javascript에도 Array.prototype.flatMap()메소드가 있다.

flatMap()메소드는 먼저 매핑함수를 사용해서 각 엘리먼트에 대해 map을 수행한다.
그 후 결과를 새로운 배열로 만든다.
depth가 1인 flat(), 그 후 map()을 실행한 것과 동일하다.

  • flat(): 모든 하위 배열 요소를 지정한 깊이까지 재귀적으로 이어붙인 새로운 배열을 생성
  • map(): 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환

map()

단일 스트림의 원소를 매핑시킨 후 매핑시킨 값을 다시 스트림으로 반환하는 중간 연산을 담당

flatMap()

  • array나 object로 감싸져 있는 모든 원소를 단일 원소 스트림으로 반환

  • 요소를 대체하는 복수 개의 요소들로 구성된 새로운 스트림을 리턴

<이것이 자바다="">에 나오는 예제 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public calss FlatMapExample {
    public static void main(String[] args) {
        List<String> inputList1 = Arrays.asList("element1 word1", "element2 word2");
        inputList1.stream()
            .flatMap(data -> Arrays.stream(data.split(" ")))
            .forEach(word -> System.out.println(word));
        //element1
        //word1
        //element2
        //word2

        List<String> inputList1 = Arrays.asList("10, 20, 30", "40, 50, 60");
        inputList2.stream()
            .flatMapToInt(data -> {
                String[] strArr = data.split(",");
                int[] intArr = new int[strArr.length];
                for(int i = 0; i< strArr.length; i++) {
                    intArr[i] = Integer.parseInt(strArr[i].trim());
                }
                return Arrays.stream(intArr);
            })
            .forEach(number -> System.out.println(number));
        //10
        //20
        //30
        //40
        //50
        //60
    }
}

음.. 이것이 flatMap을 잘 설명하는 예제인가..? 이중 배열을 쓰면 더 좋은 예제가 될 것 같다.

1
2
3
4
5
6
7
8
String[][] sample = new String[][]{
  {"a", "b"}, {"c", "d"}, {"e", "a"}, {"a", "h"}, {"i", "j"}
};

// 이중 배열에서 a찾기
Stream<String> stream = sample.stream()
  .flatMap(array -> Arrays.stream(array))
  .filter(x-> "a".equals(x));

스택오버플로우에서 말하는 map()과 flatMap()의 차이

Both map and flatMap can be applied to a Stream and they both return a Stream. The difference is that the map operation produces one output value for each input value, whereas the flatMap operation produces an arbitrary number (zero or more) values for each input value.

This is reflected in the arguments to each operation.

The map operation takes a Function, which is called for each value in the input stream and produces one result value, which is sent to the output stream.

The flatMap operation takes a function that conceptually wants to consume one value and produce an arbitrary number of values. However, in Java, it’s cumbersome for a method to return an arbitrary number of values, since methods can return only zero or one value. One could imagine an API where the mapper function for flatMap takes a value and returns an array or a List of values, which are then sent to the output. Given that this is the streams library, a particularly apt way to represent an arbitrary number of return values is for the mapper function itself to return a stream! The values from the stream returned by the mapper are drained from the stream and are passed to the output stream. The “clumps” of values returned by each call to the mapper function are not distinguished at all in the output stream, thus the output is said to have been “flattened.”

Typical use is for the mapper function of flatMap to return Stream.empty() if it wants to send zero values, or something like Stream.of(a, b, c) if it wants to return several values. But of course any stream can be returned.

구글번역기

map과 flatMap은 모두 Stream에 적용할 수 있으며 둘 다 Stream을 반환합니다. 차이점은 map 작업은 각 입력 값에 대해 하나의 출력 값을 생성하는 반면 flatMap 작업은 각 입력 값에 대해 임의의 수(0개 이상) 값을 생성한다는 것입니다.

이는 각 작업에 대한 인수에 반영됩니다.

맵 작업은 입력 스트림의 각 값에 대해 호출되고 하나의 결과 값을 생성하는 함수를 사용하여 출력 스트림으로 전송됩니다.

flatMap 작업은 개념적으로 하나의 값을 사용하고 임의의 수의 값을 생성하려는 함수를 사용합니다. 그러나 Java에서는 메소드가 0 또는 하나의 값만 리턴할 수 있기 때문에 메소드가 임의의 수의 값을 리턴하는 것은 번거롭습니다. flatMap의 매퍼 함수가 값을 가져와서 배열이나 값 목록을 반환한 다음 출력으로 보내는 API를 상상할 수 있습니다. 이것이 스트림 라이브러리라는 점을 감안할 때 임의의 수의 반환 값을 나타내는 특히 적절한 방법은 매퍼 함수 자체가 스트림을 반환하는 것입니다! 매퍼가 반환한 스트림의 값은 스트림에서 배수되고 출력 스트림으로 전달됩니다. 매퍼 함수에 대한 각 호출에 의해 반환된 값의 “덩어리”는 출력 스트림에서 전혀 구별되지 않으므로 출력이 “평탄화”되었다고 합니다.

일반적인 용도는 flatMap의 매퍼 함수가 0 값을 보내려는 경우 Stream.empty()를 반환하거나 여러 값을 반환하려는 경우 Stream.of(a, b, c)와 같은 것을 반환하는 것입니다. 그러나 물론 모든 스트림이 반환될 수 있습니다.

reference

Java8 .map()과 .flatMap()의 차이

What’s the difference between map() and flatMap() methods in Java 8?