Java

[ Java ] Stream 의 reduce 사용해보자

walwal_ 2023. 12. 20. 23:26

 

알고리즘 문제나, 개발을 하다 보면 Stream에 정의된 연산을 자주 사용하게 됩니다.

 

그중 reduce를 사용하는 방법에 대해 알아보려 합니다.

 

 


 

 

 

reduce는 스트림의 요소를 하나씩 줄여가며 계산하는 연산(reducing)입니다.

 

reduce는 forEach와 같은 최종 연산으로, 스트림 생성 후 단 한 번만 연산 가능합니다.

 

 

참고 - 스트림의 중간 연산과 최종 연산?

더보기

중간 연산은 스트림을 반환합니다. 그렇기 때문에 연속해서 연산을 이어갈 수 있습니다.

중간 연산의 종류로, distinct(), filter(), sorted(), map() 등이 있습니다.

 

최종 연산은 스트림이 아닙니다. 최종 연산을 하게 되면 스트림이 소모가 되어 연산을 추가로 진행할 수 없습니다.

최종 연산의 종류는 forEach(), count(), max(), collect(), reduce() 등이 있습니다.

 

 

 

 

 

reduce 사용

 

 

삼항연산자와 else-if를 이용해 max, min을 구하기
public class Main {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7};
        List<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6, 7));
        
        // max 값 출력 - 삼항연산자 이용
        int max = Arrays.stream(arr)
                .reduce((x, y) -> x > y ? x : y)
                .orElse(0);
        System.out.println(max); // 7
        
        // min 값 출력 - else-if 이용
        int min = Arrays.stream(arr)
                .reduce((x, y) -> {
                    if (x < y) return x;
                    else return y;
                })
                .orElse(0);
        System.out.println(min); // 1
    }
}

 

 

요소들의 합 구하기
public class Main {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7};
        List<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6, 7));
        
        // 요소들의 합 출력
        int arrSum = Arrays.stream(arr).reduce(0, (x, y) -> x + y);
        System.out.println(arrSum); // 28
    }
}

 

여기서 x와 y 가 어떤 값을 가지고 연산하여, 최종값을 도출하게 되는지 궁금해 아래 코드로 변경해 보았습니다.

public class Main {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7};
        List<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6, 7));
        
        // 요소들의 합 출력
        int arrSum = Arrays.stream(arr).reduce(0, (x, y) -> {
            System.out.println("x = " + x + ", y = " + y);// 연산순서를 알아보기 위해 출력문 삽입
            return x + y;
        });
        System.out.println(arrSum); // 28
    }
}

 

1. reduce(0, (x, y) ... )의 0 이 x 값이 됨. y는 가장 첫 요소인 1, x + y가 0 + 1로 1 이 return 됨

2. 1에서 return 된 값 1이 x 값이 됨. y는 두번째 요소인 2, x + y가 1 + 2로 3이 return 됨

3. 2에서 return 된 값 3이 x 값이 됨. y 는 세 번째 요소인 3, x + y가 3 + 3으로 6이 return 됨

... (생략)... 마지막 연산에서 x + y가 21 + 7로 28이 최종 return 됨.

 

결론 : reduce( __ , (x, y) ... )에서

__ 에 들어오는 값이

초기 x값이 됩니다.

가장 첫 요소가 초기 y값이 되며 두 요소로 연산을 진행하고, 그 연산의 결과를 이용해 다음 요소와 연산을 하게 됩니다.

 

 

요소 count
public class Main {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>(List.of(11, 02, 31, 14, 55, 16, 77));
        
        // 요소 count
        int count = list.stream().reduce(0, (x, y) -> x + 1);
        System.out.println(count); // 7
    }
}

 

마찬가지로 x와 y를 출력해 보았습니다.

public class Main {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>(List.of(11, 02, 31, 14, 55, 16, 77));
        
        // 요소 count
        int count = list.stream().reduce(0, (x, y) -> {
            System.out.println("x = " + x + ", y = " + y);
            return x + 1;
        });
        System.out.println(count); // 7
    }
}

 

 

요소들의 합에서 나온 결론과 같이, 0을 시작으로 +1 씩 진행합니다.

요소의 값이 들어오는 y와 상관없이, 연산의 return 값을 가지는 x에 +1 씩 진행하게 됩니다.

더 이상 요소가 없다면 해당 연산은 끝이 나게 되며 연산의 수만큼 카운팅이 되었음을 알 수 있습니다.