본문 바로가기

Java

(Java) Map 정렬 성능 비교 (Comparator vs Stream)

프로그래머스를 통해 알고리즘 공부를 하던 중 Map의 Value를 정렬해야 했다.

내가 생각한 방법은 두가지였으며 아래와 같다.

1. Comparator를 이용한 정렬

2. Stream을 이용한 정렬

 

문제는 아래 링크를 참조

https://programmers.co.kr/learn/courses/30/lessons/42579

 

코딩테스트 연습 - 베스트앨범

스트리밍 사이트에서 장르 별로 가장 많이 재생된 노래를 두 개씩 모아 베스트 앨범을 출시하려 합니다. 노래는 고유 번호로 구분하며, 노래를 수록하는 기준은 다음과 같습니다. 속한 노래가

programmers.co.kr

 

1. Comparator를 이용한 정렬

 

- 소스 

import java.util.*;

class Solution {
    public int[] solution(String[] genres, int[] plays) {
        int[] answer = {};
        
        /* 2021-06-07 Map안에 Map 사용 */
        Map<String, Map<Integer, Integer>> map = new HashMap<String, Map<Integer,Integer>>(); // 장르별 Map<고유번호, 플레이수>
        Map<String, Integer> totalPlayMap = new HashMap<>(); // 장르별 플레이수 총합
        
        // 데이터 적재
        for(int i=0; i<genres.length; i++) {
        	if(map.containsKey(genres[i])) {
        		map.get(genres[i]).put(i, plays[i]);
        	} else {
        		Map<Integer, Integer> temp = new HashMap<Integer, Integer>();
        		temp.put(i, plays[i]);
        		map.put(genres[i], temp);
        	}
        	totalPlayMap.put(genres[i], totalPlayMap.getOrDefault(genres[i], 0)+plays[i]);
        }
        
        /* 2021-06-09 */
        // 총 플레이수가 높은 순서대로 장르 정렬
        List<String> keySetList = new ArrayList<String>(totalPlayMap.keySet());
        // 내림차순 정렬
        Collections.sort(keySetList, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return totalPlayMap.get(o2).compareTo(totalPlayMap.get(o1));
            }
        });
        
        List<Integer> answerList = new ArrayList<Integer>();
        
        // 우선순위 장르별 상위 플레이수 정렬 및 상위 2개 추출 
        for(String key : keySetList) {
        	List<Integer> playKeyList = new ArrayList<Integer>(map.get(key).keySet());
        	
        	Collections.sort(playKeyList, new Comparator<Integer>() {
                @Override
                public int compare(Integer o1, Integer o2) {
                    return map.get(key).get(o2).compareTo(map.get(key).get(o1));
                }
            });
        	
        	int j=0;
        	for(Integer itg : playKeyList) {
        		answerList.add(itg);
        		if(++j>=2) break;
        	}
        }
        
        answer = new int[answerList.size()];
        for(int k=0; k<answer.length; k++) {
        	answer[k] = answerList.get(k);
        }
        
        return answer;
    }
}

 

- 테스트 결과

2. Stream을 이용한 정렬

- 소스

import java.util.*;

class Solution {
    public int[] solution(String[] genres, int[] plays) {
        int[] answer = {};
        
        /* 2021-06-07 Map안에 Map 사용 */
        Map<String, Map<Integer, Integer>> map = new HashMap<String, Map<Integer,Integer>>(); // 장르별 Map<고유번호, 플레이수>
        Map<String, Integer> totalPlayMap = new HashMap<>(); // 장르별 플레이수 총합
        
        // 데이터 적재
        for(int i=0; i<genres.length; i++) {
        	if(map.containsKey(genres[i])) {
        		map.get(genres[i]).put(i, plays[i]);
        	} else {
        		Map<Integer, Integer> temp = new HashMap<Integer, Integer>();
        		temp.put(i, plays[i]);
        		map.put(genres[i], temp);
        	}
        	totalPlayMap.put(genres[i], totalPlayMap.getOrDefault(genres[i], 0)+plays[i]);
        }
        
        /* 2021-06-11 Map 정렬 람다식으로 변경 */
        List<Integer> answerList = new ArrayList<Integer>();
        
        totalPlayMap.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
        .forEach(x -> {
        	String tempKey = x.getKey();
        	Map<Integer, Integer> tempMap = map.get(tempKey);
        	
        	tempMap.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).limit(2)
        	.forEach(y -> {
        		answerList.add(y.getKey());
        	});
        });
        
        answer = new int[answerList.size()];
        for(int k=0; k<answer.length; k++) {
        	answer[k] = answerList.get(k);
        }
        
        return answer;
    }
}

 

- 테스트 결과

 

> 결론

Stream을 이용한 정렬을 사용한 코드로 변경하고 나서 코드는 짧아졌지만,

Java 8부터 제공되는 Stream은 일반적인 개발자들에게 전통적인 코드보다 가독성이 떨어지며 성능 또한 떨어지는 것을 확인 할 수 있었다!

 

문제를 풀어보면서 성능에 대한 궁금증이 생겼고 결과를 직접 확인 했지만 성능 차이의 원인에 대해서는 알아 보지 못한 아쉬움이 있었고, 그 원인에 대해 공부하여 조만간 정리해야겠다!