프로그래머스 (JS)/Lv. 2

[Programmers / JS] 17680번 - [1차] 캐시 + 챗GPT를 이용한 리팩토링!

hodo- 2023. 4. 21. 18:44

Problem

문제 보기

지도개발팀에서 근무하는 제이지는 지도에서 도시 이름을 검색하면 해당 도시와 관련된 맛집 게시물들을 데이터베이스에서 읽어 보여주는 서비스를 개발하고 있다.
이 프로그램의 테스팅 업무를 담당하고 있는 어피치는 서비스를 오픈하기 전 각 로직에 대한 성능 측정을 수행하였는데, 제이지가 작성한 부분 중 데이터베이스에서 게시물을 가져오는 부분의 실행시간이 너무 오래 걸린다는 것을 알게 되었다.
어피치는 제이지에게 해당 로직을 개선하라고 닦달하기 시작하였고, 제이지는 DB 캐시를 적용하여 성능 개선을 시도하고 있지만 캐시 크기를 얼마로 해야 효율적인지 몰라 난감한 상황이다.

어피치에게 시달리는 제이지를 도와, DB 캐시를 적용할 때 캐시 크기에 따른 실행시간 측정 프로그램을 작성하시오.


Solution

function solution(cacheSize, cities) {
    //캐시 히트: 원하는 데이터가 캐시에 있을 경우
    //캐시 미스: 원하는 데이터가 캐시에 없을 경우
    
    let cache = [];
    let time = 0;
    
    for (let i of cities){
        if (cache.length < cacheSize) {
            let xCopy = i.toUpperCase();
            let cacheCopy = cache.map(x => x.toUpperCase());
            
            let index = cacheCopy.indexOf(xCopy);
            
            if(index !== -1)time++;
            else time += 5;
            
            cache.push(i);
        }
        else {
            let xCopy = i.toUpperCase();
            let cacheCopy = cache.map(x => x.toUpperCase());
            
            let index = cacheCopy.indexOf(xCopy);
            
            if(index !== -1) cache.splice(index,1);
            
            if(cache.length < cacheSize) {
                time++;
                cache.push(i);
            }
            
            else {
                time += 5;
                cache.shift();
                cache.push(i)
            }
        }
    }
    return time;
}

무사히 통과했다.

그리고 항상 문제를 풀면서 내 코드가 통과되긴 했는데..이보다 좋은 코드는 없을까? 라는 생각을 해왔고 혼자 독학하기에 절실하게 필요성을 느끼던 리팩토링을 요즘 핫한 챗GPT를 이용하여 리팩토링을 해보았다. 


  1. cache에 접근할 때 마다 toUpperCase() 함수를 사용하는 것은 성능상 비효율적입니다. 대소문자 구분 없이 도시 이름을 비교하기 위해 cache 배열에 저장되는 도시 이름들을 모두 대문자 또는 소문자로 통일시키는 것이 좋습니다. 이렇게 하면 cache 배열에 저장된 도시 이름들을 비교할 때마다 toUpperCase() 또는 toLowerCase() 함수를 사용하지 않아도 됩니다.
  2. cache 배열에 이미 존재하는 도시 이름을 추가하거나, cache 배열에서 도시 이름을 제거하는 과정에서 splice() 함수를 사용하는 것은 배열의 크기가 커질수록 성능상 비효율적입니다. 대신, cache 배열에 도시 이름이 존재하는지 여부를 판단할 때 indexOf() 함수를 사용하고, 도시 이름을 추가하거나 삭제할 때는 shift() 함수와 push() 함수를 사용하면 성능을 개선할 수 있습니다.
  3. cacheSize가 0일 경우, cache 배열에 도시 이름을 저장하지 않아도 되므로, 이 경우에는 실행 시간을 계산하지 않아도 됩니다

위는 챗GPT에게 받은 리팩토링!

세줄로 요약하자면
1. 대문자로 바꿔주는 toUpperCase()는 1번만 하라.
2. splice()함수는 성능상 비효율적이다. > 하지만 챗gpt도 비효율적이지만 splice() 함수를 대신할 함수는 없다고 한다
3. cacheSize가 0일 경우 굳이 for문(시간 계산)을 돌릴 필요가 없음

1번의 경우 원래의 도시이름 그대로 저장해주려고 새 변수를 만들어주고 거기에 대문자로 만든 문자만 저장해줬는데 리팩토링을 보고 다시 문제를 보니 실행시간만 return하면 되기에 그럴 필요가 없었다!
2번의 경우 캐시에 넣으려는 값이 이미 있다면 해당 값을 제거하는 걸로 알고 있어서 중간에 이미 문자열에 들어있는 문자를 뺄 경우 가운데에 있다면 splice를 사용해서 해당 인덱스를 1개 빼도록 해줬는데 비효율적인 건 알았지만 다른 좋은 방법이 생각 안 나서 이렇게 했는데 역시...지적을 받았다. 그래서 챗gpt에게 어떻게 풀면 좋겠냐고 물어봤는데 똑같이 splice()를 이야기하더라-_-
3번의 경우 if문으로 추가해줘서 불필요한 for문 돌리기를 하지 않을 것!!

결국 1번과 3번만 리팩토링해줬다.

function solution(cacheSize, cities) {
    //캐시 히트: 원하는 데이터가 캐시에 있을 경우
    //캐시 미스: 원하는 데이터가 캐시에 없을 경우
    
    let cache = [];
    let time = 0;
    
    if(cacheSize === 0) return cities.length * 5;
    
    for (let i of cities){
        let xCopy = i.toUpperCase();
        let cacheCopy = cache.map(x => x.toUpperCase());
        
        let index = cacheCopy.indexOf(xCopy);
        
        if (index !== -1) {
            time++;
            cache.splice(index, 1);
            cache.push(i);
        } else {
            time += 5;
            
            if (cache.length === cacheSize) cache.shift();
            
            cache.push(i);
        }
    }
    
    return time;
}

 

첫번째코드
두번째 코드

으음....그렇게 엄청 좋아진 것도 아닌 거 같고 테스트 11번의 경우에는 걸리는 시간이 더 걸렸다..ㅋㅋ 뭐지?
리팩토링이 제대로 된 게 맞나..? 
좀 더 내가 공부를 한 뒤에 다시 봐야할 거 같다ㅠ!! 

어쨌거나..챗gpt를 이용한 리팩토링 끝.



( 챗gpt 짤막한 후기를 남기자면 같은 질문을 했는데도 다른 답변을 하는 경우가 많으며 그 답변이 내가 원하는 답을 내놓지 않는 경우가 많다(위의 2번 리팩토링 결과처럼) 문제를 제대로 이해하지 못하는 경우도 있고.. 100% 신뢰를 하면 위험하며 챗gpt가 내놓은 답변이 맞는지 다시 생각하는 과정이 필요하다.)