본문 바로가기
Spring

JAVA FlatMap, Map

by windy7271 2024. 4. 20.
728x90
반응형

 

프로젝트를 진행중에

 

내 #달 근무 표를 뽑아야 했다.

출퇴근을 찍는 테이블인 Commute 가 있었고 

휴가랑, 출장, 시차근무제를 신청한경우 Attendence 테이블에 추가도 되는 식으로 진행돼서

 

이 두개를 매칭해서 내 근무표를 뽑아온다.

 

Service

public List<List<CommuteListResDto>> MonthlyAttendance(String employeeId, CommuteListReqDto commuteListReqDto) {
        Employee employee = employeeRepository.findByEmployeeId(employeeId).orElseThrow(() -> new IllegalArgumentException(" 없는 회원입니다. "));

        LocalDateTime month = commuteListReqDto.getMonth();
        Date firstDayOfMonth = Date.valueOf(month.toLocalDate().withDayOfMonth(1));
        Date lastDayOfMonth = Date.valueOf(month.toLocalDate().withDayOfMonth(month.toLocalDate().lengthOfMonth()));

//        한달간 내 출퇴근
        List<CommuteRecord> MonthCommute = commuteRepository.findAllByEmployeeAndAttendanceDateBetween(employee, firstDayOfMonth, lastDayOfMonth);
        List<Attendance> allByEmployeeAndWorkStartTimeBetween = attendanceRepository.findAllByEmployeeAndWorkStartTimeBetween(employee, month.toLocalDate().withDayOfMonth(1).atStartOfDay(), month.toLocalDate().withDayOfMonth(month.toLocalDate().lengthOfMonth()).atTime(23, 59, 59))
                .orElseThrow(()-> new IllegalArgumentException(String.valueOf(month.getMonth()) + "의 해당하는 근무표가 없습니다."));

        return allByEmployeeAndWorkStartTimeBetween.stream()
                .map(x -> CommuteListResDto.toDto(x, MonthCommute))
                .collect(Collectors.toList());
    }

 

 

DTO

public static List<CommuteListResDto> toDto(Attendance attendance, List<CommuteRecord> commuteRecords) {
    List<CommuteListResDto> result = new ArrayList<>(); // 결과를 저장할 리스트 생성
    CommuteListResDtoBuilder builder = CommuteListResDto.builder(); // 빌더 객체 생성

    if (O04.name().equals(attendance.getWorkPolicy()) || O03.name().equals(attendance.getWorkPolicy()) || O09.name().equals(attendance.getWorkPolicy())) {
        LocalDate startDate = attendance.getWorkStartTime().toLocalDate(); // 휴가 시작
        LocalDate endDate = attendance.getWorkEndTime().toLocalDate(); // 휴가 종료
        while (!startDate.isAfter(endDate)) {
            CommuteListResDto dto = builder // 빌더를 사용하여 객체 생성
                    .attendanceDate(Date.valueOf(startDate))
                    .workPolicy(attendance.getWorkPolicy())
                    .workStartTime(attendance.getWorkStartTime())
                    .workEndTime(attendance.getWorkEndTime())
                    .tardy("휴가 혹은 병가 혹은 출장")
                    .build();

            result.add(dto);

            // 다음 날짜
            startDate = startDate.plusDays(1);
        }
    } else {
        Date day = Date.valueOf(attendance.getWorkStartTime().toLocalDate());
        CommuteRecord commuteRecord = commuteRecords.stream()
                .filter(x -> x.getAttendanceDate().equals(day))
                .findFirst().orElseThrow(() -> new IllegalArgumentException("매칭되는 날짜가 없습니다."));
        CommuteListResDto dto = builder
                .attendanceDate(day)
                .workPolicy(attendance.getWorkPolicy())
                .workStartTime(attendance.getWorkStartTime())
                .tardy("시차 반차")
                .build();

        result.add(dto);

    }

    return result;
}

 

 

 

만약 4월20일 부터 4월 25일 까지 휴가가 등록 되어 있으면

Commute 테이블에 4/20 ~ 4/25일의 출퇴근 기록은 없다. 

그러면 Attendance에서 가져와서 4/20 ~ 4/25 일은 휴가로 만들어준다.

근데 기존 builder 를 사용해서 하면 4/20 일 꺼만 만들어지기 때문에 list를 사용해준다.

 

일반 map 사용

map

일반 map 사용시 휴가인 4/20 ~ 4/24 일까지는 이차원 리스트로 들어간다.

관리하기 어려워 

FlatMap을 사용하기로 했다.

 

 

return allByEmployeeAndWorkStartTimeBetween.stream()
        .flatMap(attendance -> CommuteListResDto.toDto(attendance, MonthCommute).stream())
        .collect(Collectors.toList());

return 부분이 이렇게 바뀌게 된다.

리턴 타입도 List가 하나 빠지게된다.

 

FlatMap

 

Map vs flatMap

map()은 단일 스트림의 원소를 매핑시킨 후 매핑시킨 값을 다시 스트림으로 변환하는 중간 연산이다. 1:1 로 매칭해서 변환한다.

 

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> x = numbers.stream()
                                      .map(x -> x * x)
                                      .collect(Collectors.toList());
// x: [1, 4, 9, 16, 25]

 

flatMap() 은 map() + Flattening(펼친다)

flatMap은 각 요소에 대해 매핑 함수를 적용하여 생성된 각각의 결과 스트림을 하나의 스트림으로 연결한다. 각 요소에 대해 1:N 또는 0:N 매핑을 수행하기 때문에  각 요소마다 여러 개의 결과가 생성될 수 있다. 반환된 스트림은 평평하게(1차원) 펼쳐진 결과이다.

 

List<String> lines = Arrays.asList("hello world", "goodbye world", "welcome home");
List<String> words = lines.stream()
                         .map(line -> line.split("\\s+")) // 각 줄을 단어로 분할하여 스트림의 스트림을 생성
                         .flatMap(Arrays::stream) // 각 스트림을 하나의 스트림으로 평평하게 펼침
                         .collect(Collectors.toList());
// words: ["hello", "world", "goodbye", "world", "welcome", "home"]

 

 

리스트나 2차원 리스트도 1차원 리스트로 펼칠 수 있다.

 

flatMap

 

 

 

 

 

반응형

댓글