TIL (20210813) - Collection 정렬 (feat. Map, Set, sorted, LinkedHashMap)

Joshua_Kim·2021년 8월 13일
2

📖 TIL

목록 보기
3/8
post-thumbnail

🌱 서론

  • java에서는 collection을 다루는 것이 정말 중요하다. 많이 중요해 정말.

  • 실무에서 특히 stream을 요즘 많이 사용하고 있는데, 약간 복잡한 요구사항을 stream으로 간단하게 풀어낸 코드가 있어서 기록하고자 한다.

👉 요구사항

  • 현재 최종적으로 return되는 ReturnDtoMap<String, CategoryModifiedDto> 형식이다.

  • 사실, 이 프로젝트에서는 DTO가 매우 복잡한데, 오늘 주제가 DTO가 아니므로 간단히 DTO 설계에 대해 설명하자면, Entity에서 set인 데이터를 최종 return되는 데이터에서는 Map으로 담아야 하고, 무한루프를 돌지 않도록 또다른 Dto를 만들어서 뱉어내는 데이터를 잘라냈다.

  • 이런 설계 상황에서, 데이터가 넘어갈 때, 정렬이 되지 않은 채로 넘어가게 되었는데, 이것을 데이터가 DB에 저장된 순서대로 넘겨달라는 요구사항이 들어왔다.

🗝 요구사항 해결 process

1. 데이터 정렬 기준 정하기

  • DB에 저장된 데이터를 확인해보니 모든 데이터가 일관된 Date로 들어와 있었다.

  • 초까지 똑같이 들어와있다 🤔
  • 우리 회사에서는 데이터를 정제하여 넘겨주는 크롤링 팀이 따로 있는데, 그곳에서 아마 한번에 데이터를 수집하여 저장시키기 때문에 데이터를 저장하는 초마저 정확하게 똑같이 들어갔다.

  • 고민 끝에 우선 크롤러 팀에게 데이터 수집이 해당 사이트의 순서대로 수집이 되어 들어간 것인지를 확인했고, 데이터 정렬 기준을 id 값으로 하기로 정했다. 데이터가 들어간 시간은 같지만, id는 고유하고 어쨌든 데이터는 ordered되어서 들어가는 것이므로 id로 정렬하게 되었다.

2. 자, 그럼 어디 한 번 정렬해볼까?

  • 1차 시도 (feat. 무식한 방법... 🥲)
    public static LinkedHashMap<String, CategoryModifiedDto> sortMapById(Map<String, CategoryModifiedDto> map) {
        List<Map.Entry<String, CategoryModifiedDto>> entries = new LinkedList<>(map.entrySet());
        Collections.sort(entries, (o1, o2) -> o1.getValue().getCategory_id()
        .compareTo(o2.getValue().getCategory_id()));
       	LinkedHashMap<String, CategoryModifiedDto> result = new LinkedHashMap<>();
        for (Map.Entry<String, CategoryModifiedDto> entry : entries) {
        	result.put(entry.getKey(), entry.getValue());
        }
        return result;
    }
  • 일단 머릿속에 있는 로직의 흐름대로 코딩을 했다.
  • sortMapById라는 메소드를 하나 생성하여 파라미터로 기존의 생성된 Map<String, CategoryModifiedDto>타입의 객체를 하나 받는다.
  • 그 후에 List<Map.Entry>>타입의 LinkedList를 생성하고, 그곳에서 getCategory_id()를 기준으로 정렬을 해준다.
  • 최종적으로 returnLinkedHashMap 객체를 생성해주고, for 루프를 통해 result 인스턴스에 담아주어 메소드를 리턴한다.
  • 초큼...복잡해 보이지만, 머리속에 있는 로직의 흐름대로 좌르륵 만들어보았다.
  • 그런데 코드를 보고있자니 너무 복잡하기도하고 리스트로 담았다가 다시 맵에 담았다가..낭비되는 부분이 많아 보인다. stream에서 하지 못하나..? 라는 생각이 들었고, 극한의 효율을 뽑아내기위해 CategoryDto에서 stream을 건들여보았다.
  • 2차 시도 (feat. 갓갓 stream 👍) .. 이게...되네?
public CategoryDto(Category entity) {
        super(entity);
        children = new HashMap<>();
        this.children = entity.getChildrenCategory().stream()
        	.sorted(Comparator.comparing(Category::getId))
                .collect(Collectors
                .toMap(Category::getCategoryName, CategoryModifiedDto::new, 
                	(x, y) -> x, LinkedHashMap::new));
  • this.childrenMap<String, CategoryModifiedDto> 타입이다.
  • getChildrenCategory()Set<Category>타입이다.
  • 딱 보기만 해도 코드가 너무나 깔끔해졌다.

  • 우선, setstream()을 통해 판을 깔고, sorted로 정렬 순서를 정해줬다. 극한의 코드 효율을 위해 lambda를 사용했다. (람다 간지)

  • 그 후에 다시 이 setmap으로 변환시켜줬는데, key값으로 CategoryName을 가져왔고, value값으로 CategoryModifiedDto를 생성자에 set의 들어가 있는 Category 인스턴스들을 넣어 생성자로 초기화시켜주었다.

  • 그 다음은 그냥 Map으로 변환하는것이아니라 LinkedHashMap으로 변환을 시켜주어야 하기 때문에 넣은 코드다. Map으로 가게되면 정렬한 것이 다시 흐트러져 들어가게 된다. 그렇기 때문에, LinkedHashMap으로 넣어주고 this.children을 완성해주면 된다.

🙏 오늘의 TIL을 마치며

  • 결론 : stream은 짱이다. 갓갓 너무 편하다.

  • 그럼 이만~ ! ✋

profile
인문학 하는 개발자 💻

0개의 댓글