티스토리 뷰

Backend/Java8

#27 Advanced Stream - Reduce

RadderNepa 2022. 10. 16. 00:07

● 도입

- Stream 안의 데이터에 주어진 함수를 반복 적용해 데이터를 '하나의 값으로 합치는' 작업

(데이터가 하나만 남을 때까지 계속 적용)
- 최종적으로 남은 데이터를 return 한다.
- Max / Min / Count도 reduce의 일종이다.

출처 - The Red: 25개 백엔드 개발 필수 현업 예제를 통해 마스터하는 JAVA STREAM(fastcampus)

- 위의 사진은 아래와 같은 방식으로 실행되는 것이다.

f(x, y)의 결과 = a  →  f(a, z)의 결과 = b  →  f(b, ...)      * f 는 동일한 함수이다.

- 이러한 작업이 계속 반복되면서 결국에는 하나의 데이터만 남는 것이다.(해당 데이터가 return 된다.)

 

1.

Optional<T> reduce(BinaryOperator<T> accumulator);

- 주어진 accumulator를 Stream 안의 모든 데이터에 반복 적용을 해서 최종적으로 하나의 값을 도출한다.
- Stream이 비어있을 경우 빈 Optional을 반환

cf) BinaryOperator?

- BiFunction<T, U, R>에서 <T, U, R> 3개의 타입이 모두 같을때 대신하여 사용할 수 있다.

- input type과 output type이 모두 동일한 BiFunction이라고 생각하면 된다.

 

2.

T reduce(T identity, BinaryOperator<T> accumulator);

- 주어진 초기값과 accumulator를 이용, Stream 안의 모든 데이터에 반복 적용을 해서 최종적으로 하나의 값을 도출한다.

- 반복 작업에 대한 초기값을 제공한다.  →  T identity

- 주어진 초기값을 가지고 reduce 작업을 시작하는 것이다.

- 초기값이 있기 때문에 항상 반환값이 존재하며 그렇기에 반환 타입이 Optional<T> 이 아니라 T reduce 이다.

 

3.

<U> U reduce(U identity
                        , BiFunction<U, ? super T, U> accumulator
                        , BinaryOperator<U> combiner);

- U identity  →  U type의 초기값을 준다.
- BiFunction<U, ? super T, U> accumulator  →  Stream 안의 T type의 데이터와 계속 합쳐서 U type의 결과물을 만들어낸다.
- BinaryOperator<U> combiner  →  병렬 작업시 필요

- reduce 작업에서 type이 바뀌는 경우에 사용(합치는 과정에서 타입이 바뀔 경우 사용)

- Map + reduce로 대체 가능하기에 해당 method는 많이 쓰이지는 않는다.

→  Map을 이용해 U type의 데이터로 바꾼 후

→  그 후에 reduce 작업

 

 

● 실습

1.

package com.fastcampus.functionalprogramming.chapter8;

import java.util.Arrays;
import java.util.List;

import com.fastcampus.functionalprogramming.chapter8.model.User;

public class Chapter8Section4 {
	public static void main(String[] args) {
		// reduce를 이용해 Integer List의 합을 구해보자
		List<Integer> numbers = Arrays.asList(1, 4, -2, -5, 3);
		
		int sum = numbers.stream()
				.reduce((x, y) -> x + y)
				.get(); // Optional을 return 하기에 get()을 이용해 꺼낸다.
		System.out.println("총합 : " + sum);
		
		// min을 reduce를 이용해 구해보자
		int min = numbers.stream()
				.reduce((x, y) -> (x > y) ? y : x).get();
		System.out.println("가장 적은 수 : " + min);
// ===================================================================================================
		// 초기값을 제공
		List<Integer> numbers2 = Arrays.asList(1, 4, -2, -5, 3);
		int product = numbers2.stream()
					.reduce(1, (x, y) -> x * y); // 초기값으로 1 을 제공, 초기값이 있기에 get()을 쓰지 않아도 된다.
		System.out.println("곱 : " + product);
// ===================================================================================================
		// String으로 담겨있는 숫자의 합을 구하자
		List<String> numberStrList = Arrays.asList("3", "2", "5", "-4");
		
		// map + reduce
		int sumOfNumberStrList = numberStrList.stream()
				.map(x -> Integer.parseInt(x))
				.reduce(0, (x, y) -> x + y);
		System.out.println("sumOfNumberStrList : " + sumOfNumberStrList);
		
		// <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner); 이용
		// U type은 Integer / T type은 String 이다.
		// map + reduce 보다 복잡해 보이긴하다. 그래서 해당 method는 잘 사용하지는 않는다.
		int sumOfNumberStrList2 = numberStrList.stream()
				.reduce(0, (number, str) -> number + Integer.parseInt(str), (num1, num2) -> num1 + num2);
		System.out.println("sumOfNumberStrList2 : " + sumOfNumberStrList2);
	}
}

 

2. 각 user들의 친구 수 총합을 구해보자

package com.fastcampus.functionalprogramming.chapter8;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

import com.fastcampus.functionalprogramming.chapter8.model.Order;
import com.fastcampus.functionalprogramming.chapter8.model.OrderLine;
import com.fastcampus.functionalprogramming.chapter8.model.User;

public class Chapter8Section4 {
	public static void main(String[] args) {
		User user1 = new User()
				.setId(101)
				.setName("Alice")
				.setFriendUserIds(Arrays.asList(201, 202, 203, 204));	// 친구 4명
	    User user2 = new User()
	    		.setId(102)
	    		.setName("Bob")
	    		.setFriendUserIds(Arrays.asList(204, 205, 206));		// 친구 3명
	    User user3 = new User()
	    		.setId(103)
	    		.setName("Charlie")
	    		.setFriendUserIds(Arrays.asList(204, 205, 207));		// 친구 3명
	    
	    List<User> users = Arrays.asList(user1, user2, user3);
	    
	    // 각 user들의 친구 수 총합을 구해보자
	    int sumOfNumberOfFriends = users.stream()
	    							.map(User::getFriendUserIds)
	    							.map(List::size)
	    							.reduce(0, (x, y) -> x + y);
	    System.out.println("친구 몇 명? " + sumOfNumberOfFriends);
	}
}

 

3. 각 order의 OrderLine 들의 총합을 구해보자

package com.fastcampus.functionalprogramming.chapter8;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

import com.fastcampus.functionalprogramming.chapter8.model.Order;
import com.fastcampus.functionalprogramming.chapter8.model.OrderLine;
import com.fastcampus.functionalprogramming.chapter8.model.User;

public class Chapter8Section4 {
	public static void main(String[] args) {
	    // 숙제
	    Order order1 = new Order()
	    		.setId(1001L)
	    		.setOrderLines(Arrays.asList(
	    				new OrderLine().setAmount(BigDecimal.valueOf(1000)),
	    				new OrderLine().setAmount(BigDecimal.valueOf(2000))));
	    
        Order order2 = new Order()
        		.setId(1002L)
        		.setOrderLines(Arrays.asList(
        				new OrderLine().setAmount(BigDecimal.valueOf(2000)),
        				new OrderLine()
        				.setAmount(BigDecimal.valueOf(3000))));
        
        Order order3 = new Order()
        		.setId(1002L)
        		.setOrderLines(Arrays.asList(
        				new OrderLine().setAmount(BigDecimal.valueOf(1000)),
        				new OrderLine().setAmount(BigDecimal.valueOf(2000))));
        
        List<Order> orders = Arrays.asList(order1, order2, order3);
        
        // 각 order의 OrderLine 들의 총합을 구해보자
        BigDecimal sumOfAmounts = orders.stream()
        	.map(Order::getOrderLines)	// Stream<List<OrderLine>>
        	.flatMap(List::stream)		// Stream<OrderLine>
        	.map(OrderLine::getAmount)	// Stream<BigDecimal>
        	.reduce(BigDecimal.ZERO, BigDecimal::add);
        	// .reduce(BigDecimal.ZERO, (x, y) -> x.add(y));
        
        System.out.println("sumOfAmounts : " + sumOfAmounts);
	}
}

 

 

cf) java BigDecimal 연산

https://cofs.tistory.com/339

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
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
글 보관함