-
자료구조 효율성에 대한 고민내일배움캠프 2023. 3. 7. 22:26
새벽까지 문제 해결 안되다 해결된 나의 모습 딱 저 표정이였던것 같습니다. 어제 PartyPost 연관관계 때문에 삭제가 안되서 밤이라 머리가 잘 안돌아가는건지
entity 에 아래 코드를 추가하고 와 이제 삭제되겠구나 큰 착각을 했었습니다 ㅠ..
public void clearApplications() { this.applications.clear(); }
안되서 빙빙 돌아 뭐가 문제일까 보니까 해당 Repository 에 저장된 Application 을 삭제 한게 아니라서 인걸
깨닫고 어제 리뷰한것 처럼 마무리 했습니다.
오늘의 사진을 설명하느라 별걸 다 말하게 되네요
↓↓↓↓↓↓↓↓↓↓ NoShow 처리를 위한 자료 구조 고민 ↓↓↓↓↓↓↓↓↓↓
처음 이중 배열로 처리하려 했다가 시행착오 끝에 아래로 방향을 바꿧습니다
NoShow 와 User, PartyPost 연관관계를 맺고 User 객체에 NoShowCnt를 넣어서 처리하려고 했으나 제한사항이 많고PartyPost를 삭제하려 할 때 연관관계를 맺어줄 시 해당 NoShow들을 삭제해야 하기에 Id 값으로 받았고 DB에 저장했습니다.
public NoShow(Long reporterId, Long reportedId, Long partyPostId) { this.reporterId = reporterId; this.reportedId = reportedId; this.partyPostId = partyPostId; }
id 값만 받게 되니 어떻게 처리해야 되나 고민중에 ArrayList 각 배열에 reportedId 를 중복되는지 체크하고 넣고 uniqueRerpotedIds 에 넣어줬습니다
List<Long> uniqueReportedIds = new ArrayList<>(joinUserSize); for (NoShow noShow : noShowList) { Long reportedId = noShow.getReportedId(); if (!uniqueReportedIds.contains(reportedId)) { uniqueReportedIds.add(reportedId); } }
다음 기능을 만들다가 굳이 contains 로 중복을 체크 하는게 아닌 처음부터 중복을 허용하지 않는 hashset 을 사용하여 단순화 하는게 좋겠다 생각해서 아래 처럼 로직을 수정했습니다.
Set<Long> uniqueReportedIds = new HashSet<>(); for (NoShow noShow : noShowList) { Long reportedId = noShow.getReportedId(); uniqueReportedIds.add(reportedId); }
끝으로 아래 로직을 추가하여 구현을 완료했는데
for (Long reportedId : uniqueReportedIds) { int noShowCnt = 0; for (NoShow noShow : noShowList) { if (noShow.getReportedId().equals(reportedId)) { noShowCnt ++; } } if (noShowCnt >= Math.round(joinUserSize/2.0)) { User reported = findByUser(reportedId); reported.getProfile().plusNoShowCnt(); } }
reportedId 가 key 역활을 하고 있어서 Map 으로 바꿔도 좋겠다 판단했고 수정했습니다 똑같이 reportedId 를 key 값으로 주고 해당 값이 없으면 ArrayList 를 추가하고 noShow를 넣었습니다
List<NoShow> noShowList = noShowRepository.findAllByPartyPostId(partyPost.getId()); Map<Long, List<NoShow>> reportedNoShowMap = new HashMap<>(); for (NoShow noShow : noShowList) { Long reportedId = noShow.getReportedId(); reportedNoShowMap.computeIfAbsent(reportedId, k -> new ArrayList<>()).add(noShow); }
그 다음 Map.Entry 를 사용하여 key, value 를 가져와서 value 를 비교하고 cnt 를 올리며 마무리 지었습니다.
for (Map.Entry<Long, List<NoShow>> entry : reportedNoShowMap.entrySet()) { Long reportedId = entry.getKey(); List<NoShow> reportedNoShowList = entry.getValue(); int noShowReportCnt = reportedNoShowList.size(); if (noShowReportCnt >= Math.round(joinUserSize / 2.0)) { User reported = findByUser(reportedId); reported.getProfile().plusNoShowCnt(); } }
결과적으로 ArrayList, Hashset 을 사용할 때 보다 최소 한번의 목록에 대한 반복이 줄었네요.예상과 다른 결과가 있어 이어서 작성했습니다. ↓↓↓↓↓ 클릭 ↓↓↓↓↓
ArrayList, HashSet, HashMap 성능 비교
90 TIL 에 적었던 내용에 문제가 있어서 이어서 작성하겠습니다. 코드 상으로 보기에 목록을 한번 이상 덜 불러와 빠를 것이다 라고 착각을 했습니다. 문뜩 한번 실험해 봐야겠다 생각이 들었고
holloweyed-snail.tistory.com
아래는 전체 코드입니다.
@Transactional public void checkingNoShow(List<PartyPost> posts) { for (PartyPost partyPost : posts) { partyPost.ChangeStatusEnd(); int joinUserSize = partyPost.getApplications().size(); List<NoShow> noShowList = noShowRepository.findAllByPartyPostId(partyPost.getId()); Map<Long, List<NoShow>> reportedNoShowMap = new HashMap<>(); for (NoShow noShow : noShowList) { Long reportedId = noShow.getReportedId(); reportedNoShowMap.computeIfAbsent(reportedId, k -> new ArrayList<>()).add(noShow); } for (Map.Entry<Long, List<NoShow>> entry : reportedNoShowMap.entrySet()) { Long reportedId = entry.getKey(); List<NoShow> reportedNoShowList = entry.getValue(); int noShowReportCnt = reportedNoShowList.size(); if (noShowReportCnt >= Math.round(joinUserSize / 2.0)) { User reported = findByUser(reportedId); reported.getProfile().plusNoShowCnt(); } } } }