[프로그래머스 | 파이썬 / 자바스크립트] [3차] 파일명 정렬(2018 KAKAO BLIND RECRUITMENT / level 2)

2023. 3. 15. 14:06·Problem Solving/프로그래머스
반응형
문제

https://school.programmers.co.kr/learn/courses/30/lessons/17686

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

🐍파이썬
def solution(files):
    answer = []
    head = ''
    number = ''
    tail = ''
    for i in files:
        for j in range(len(i)):	#파일의 문자를 하나씩 확인
            if i[j].isdigit():	#숫자가 나오면
                head = i[:j]	#숫자 앞까지 끊어서 head
                number = i[j:]	#숫자부터는 number
                for k in range(len(number)):	#number/tail 구분
                    if number[k] in [" ", ".", "-"]:	#구분자가 나오면
                        tail = number[k:]	#구분자부터 tail
                        number = number[:k]	#구분자 이전은 number, number를 먼저 변경해버리면 tail값이 이상하게 나오므로 주의
                        break	#그 이후에 나오는 구분자는 처리하지 않기 위해 break
                answer.append([head, number, tail])	#head, number, tail값이 처리되면 이를 배열에 저장
                head = ''	#다음 for문을 위해 변수 초기화
                number = ''
                tail = ''
                break	#다음 문자가 숫자일 경우 반복문이 또다시 실행되므로 실행중지를 위해 break
    answer.sort(key = lambda x:(x[0].lower(), int(x[1])))	#head값을 기준으로 정렬 후 number값을 기준으로 정렬
    return [''.join(i) for i in answer]

거의 대부분 풀이를 참고했다...

  • 참고한 풀이: https://tinyurl.com/2zvfsnhu
  • 람다 참고 블로그: https://velog.io/@aonee/Python-%EC%A0%95%EB%A0%AC-sort-sorted-reverse

 

 

다른 풀이 방법

import re
def solution(files):
    a = sorted(files, key=lambda file : int(re.findall('\d+', file)[0]))
    b = sorted(a, key=lambda file : re.split('\d+', file.lower())[0])
    return b

정규표현식 사용

  • '\d+' : 하나 혹은 그 이상 연결된 숫자
  • 정규표현식 정리 블로그: https://tinyurl.com/2g2omnte

re모듈

findall(패턴, 문자열, 플래그)

문자열 안의 패턴에 맞는 케이스를 전부 찾아서 리스트로 반환

참고: https://brownbears.tistory.com/506


def head_compare(data):    
    route = 0
    answer = ['', '']
    for i, v in enumerate(data):
        if (route == 0):
            if (v.isnumeric() == True):	#숫자일 때
                answer[0] = data[:i].lower()	#head
                route = 1
                answer[1] += v	#현재 문자를 저장(number)
        elif (route == 1):
            if (v.isnumeric() == True): #숫자일 경우
                answer[1] += v  #현재 문자를 저장(number)
            else:   #숫자가 아닐 경우(tail)
                break   #반복문 종료
    answer[1] = int(answer[1])  #문자열을 숫자로 변경
    return answer
    # answer = [['f-', 5], ['b-', 50], ['a-', 10], ['f-', 14]]

def solution(files):
    answer = []
    files.sort(key = lambda x:head_compare(x))
    return files

 

 

🐥자바스크립트
더보기

❌ 오답

function solution(files) {
    let sortArr = [];
    for(let i = 0; i < files.length; i++){
        let answer = ['', '', '', i]
        for(let j = 0; j < files[i].length; j++){
            if(isNaN(files[i][j]) === false){
                answer[0] = files[i].slice(0, j);
                answer[1] = files[i].slice(j);
                for(let k = 0; k < answer[1].length; k++){
                    if(answer[1][k] === " " || answer[1][k] === "." || answer[1][k] === "-"){
                        answer[2] = answer[1].slice(k);
                        answer[1] = answer[1].slice(0, k);
                        break;
                    }
                }
                sortArr.push(answer);
                break;
            }
        }
    }
    return sortArr.sort((a, b)=>{
        if(a[0].toLowerCase() > b[0].toLowerCase()){
            return 1;
        } else if(a[0].toLowerCase() < b[0].toLowerCase()){
            return -1;
        } else if(parseInt(a[1]) - parseInt(b[1]) !== 0){
            return parseInt(a[1]) - parseInt(b[1]);
        } else {
            return a[3] - b[3];
        }
    }).map((i) => [i[0], i[1], i[2]].join(''));
}
function solution(files) {
    let sortArr = [];
    for(let i = 0; i < files.length; i++){
        let answer = ['', '', '', i]	//head, number, tail, index 담는 변수
        for(let j = 0; j < files[i].length; j++){
            if(isNaN(parseInt(files[i][j])) === false){
                answer[0] = files[i].slice(0, j);	//0~j-1번째 인덱스까지 head
                answer[1] = files[i].slice(j);	//j~끝 인덱스까지 number
                for(let k = 0; k < answer[1].length; k++){	//number에서 number, tail분리
                    if(answer[1][k] === " " || answer[1][k] === "." || answer[1][k] === "-"){	//특수기호 뒤는 tail
                        answer[2] = answer[1].slice(k);
                        answer[1] = answer[1].slice(0, k);	//특수기호 앞까지 number
                        break;
                    }
                }
                sortArr.push(answer);	//[head, number, tail, index]를 sortArr에 push
                break;
            }
        }
    }
    return sortArr.sort((a, b)=>{
    	//head 오름차순 정렬
        if(a[0].toLowerCase() > b[0].toLowerCase()){
            return 1;
        } else if(a[0].toLowerCase() < b[0].toLowerCase()){
            return -1;
        //number 오름차순 정렬
        } else if(parseInt(a[1]) - parseInt(b[1]) !== 0){
            return parseInt(a[1]) - parseInt(b[1]);
        //head, number 동일 시 index값으로 오름차순 정렬(들어온 시간 순서대로 정렬)
        } else {
            return a[3] - b[3];
        }
    //index값을 제외하고 join해서 맵핑 후 출력
    }).map((i) => [i[0], i[1], i[2]].join(''));
}

 

➕ 아래와 같이 index를 추가하지 않아도 답으로 인정된다.

function solution(files) {
    let sortArr = [];
    for(let i = 0; i < files.length; i++){
        let answer = ['', '', '']	//head, number, tail 담는 변수
        for(let j = 0; j < files[i].length; j++){
            if(isNaN(parseInt(files[i][j])) === false){
                answer[0] = files[i].slice(0, j);	//0~j-1번째 인덱스까지 head
                answer[1] = files[i].slice(j);	//j~끝 인덱스까지 number
                for(let k = 0; k < answer[1].length; k++){	//number에서 number, tail분리
                    if(answer[1][k] === " " || answer[1][k] === "." || answer[1][k] === "-"){	//특수기호 뒤는 tail
                        answer[2] = answer[1].slice(k);
                        answer[1] = answer[1].slice(0, k);	//특수기호 앞까지 number
                        break;
                    }
                }
                sortArr.push(answer);	//[head, number, tail]을 sortArr에 push
                break;
            }
        }
    }
    return sortArr.sort((a, b)=>{
    	//head 오름차순 정렬
        if(a[0].toLowerCase() > b[0].toLowerCase()){
            return 1;
        } else if(a[0].toLowerCase() < b[0].toLowerCase()){
            return -1;
        //number 오름차순 정렬
        } else if(parseInt(a[1]) - parseInt(b[1]) !== 0){
            return parseInt(a[1]) - parseInt(b[1]);
        //head, number 동일 시 기존순서 유지
        } else {
            return 0;
        }
    //배열의 값을 join해서 맵핑 후 출력
    }).map((i) => i.join(''));
}
if(isNaN(parseInt(files[i][j])) === false)​

parseInt 하나때문에 문제 푸는 데 1시간 반 이상을 더 소요했다...
왜 isNaN만 사용했을 때는 오류가 뜨는지 궁금해서 parseInt와 isNaN의 차이점을 찾아보았다.

💡 parseInt와 isNaN의 차이점
1️⃣ isNaN takes an integer as an argument - therefore JS converts "" to 0
(isNaN은 정수를 인수로 가진다. - 따라서 인수의 ""(빈 문자열)은 0으로 취급되어 false가 리턴된다.)
2️⃣ parseInt takes a string as an argument - therefore an empty string is not a number
(parseInt는 string을 인수로 가진다 - 따라서 인수의 ""(빈 문자열)은 숫자로 취급되지 않는다.)
출처: https://stackoverflow.com/questions/8271836/isnan-vs-parseint-confusion


💡 isNaN함수 사용시 주의할 점

//isNaN 단독 사용 시
console.log(isNaN(" ")); // false
console.log(isNaN(".")); // true
console.log(isNaN("number")); // true
console.log(isNaN("2.19")); // false
console.log(isNaN("")); // false
console.log(isNaN(null)); // false

//parseInt로 감싼 경우
console.log(isNaN(parseInt(" "))); // true
console.log(isNaN(parseInt("."))); // true
console.log(isNaN(parseInt("number"))); // true
console.log(isNaN(parseInt("2.19"))); // false
console.log(isNaN(parseInt("")));	// true
console.log(isNaN(parseInt(null)));	// true
isNaN 함수의 인수가 Number 형이 아닌 경우, 그 값은 먼저 숫자로 강제됩니다. 결과값은 그 뒤에 NaN인지 결정하기 위해 테스트됩니다. 따라서 숫자 형으로 강제된 결과 유효한 비NaN 숫자값(특히 강제될 때 숫자값이 0 또는 1을 주는 빈 문자열 및 boolean 원시형)이 되는 비숫자의 경우, "false" 반환값은 예기치 않을 수 있습니다;
(출처: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/isNaN)
(추가로 참고하면 좋을 블로그: https://mygumi.tistory.com/335)

👉 다양한 테스트 케이스에서 숫자가 아닌 원소가 false를 리턴하여 오류가 생긴 듯 하다...

 

 

다른 풀이 방법

function solution(files) {
    let answerWrap = files.map((file, index) => ({file, index}));
    const compare = (a, b) => {
      const reg = /(\D*)([0-9]*)/i;
      const A = a.match(reg);
      const B = b.match(reg);
      const compareHead = A[1].toLowerCase().localeCompare(B[1].toLowerCase());	//head 비교(오름차순)
      const compareNumber = (a, b) => {	//number 비교(오름차순)
         return parseInt(a) > parseInt(b) ? 
            1 : parseInt(a) < parseInt(b) ? 
             -1 
            : 0
      }
      return compareHead === 0 ? compareNumber(A[2], B[2]) : compareHead	//head동일할 경우 number로 정렬
    }
    answerWrap.sort((a, b) => {
      const result = compare(a.file, b.file);
      return result === 0 ? a.index - b.index : result;	//head, number 동일할 경우 index로 정렬
    })
    return answerWrap.map(answer => answer.file);
}

정규표현식을 사용한 풀이.

정규표현식 참고 블로그: https://heropy.blog/2018/10/28/regexp/

 

정규표현식, 이렇게 시작하자!

매일 쓰는 것도, 가독성이 좋은 것도 아니지만, 모르면 안되는 정규표현식. 저는 이렇게 공부하기 시작했습니다! (자바스크립트를 기준으로 설명합니다)

heropy.blog

 

💡 match()

문자열이 정규식과 매치되는 부분을 검색하는 메서드

 

💡 localeCompare()

참조 문자열이 정렬 순으로 지정된 문자열 앞 혹은 뒤에 오는지 또는 동일한 문자열인지 나타내는 수치를 반환하는 메서드

localeCompare(compareString)
localeCompare(compareString, locales)
localeCompare(compareString, locales, options)

매개변수

  • compareString: referenceStr가 비교되는 문자열
  • locales: 기준 언어(독일어, 스웨덴어 등...)
  • options: localeCompare()이 제공하는 결과를 options를 통해 사용자 정의 가능

반환 값

compareString 전에 referenceStr가 위치하는 경우 음수, compareString 후에 referenceStr가 위치하는 경우 양수, 동등할 경우 0

 

반응형
저작자표시 비영리 변경금지 (새창열림)

'Problem Solving > 프로그래머스' 카테고리의 다른 글

[프로그래머스 | 파이썬 / 자바스크립트] 추억 점수(연습문제 / level 1)  (0) 2023.03.31
[프로그래머스 | 파이썬 / 자바스크립트] 평행(코딩테스트 입문 / level 0)  (0) 2023.03.16
[프로그래머스 | 파이썬 / 자바스크립트] 다리를 지나는 트럭(스택/큐 / level 2)  (0) 2023.03.16
[프로그래머스 | 파이썬 / 자바스크립트] 덧칠하기(연습문제 / level 2)  (0) 2023.03.12
[프로그래머스 | 파이썬 / 자바스크립트] 겹치는 선분의 길이(코딩테스트 입문/ level 0)  (0) 2023.03.12
[프로그래머스 | 파이썬 / 자바스크립트] [3차] 압축(2018 KAKAO BLIND RECRUITMENT/ level 2)  (2) 2023.03.11
'Problem Solving/프로그래머스' 카테고리의 다른 글
  • [프로그래머스 | 파이썬 / 자바스크립트] 평행(코딩테스트 입문 / level 0)
  • [프로그래머스 | 파이썬 / 자바스크립트] 다리를 지나는 트럭(스택/큐 / level 2)
  • [프로그래머스 | 파이썬 / 자바스크립트] 덧칠하기(연습문제 / level 2)
  • [프로그래머스 | 파이썬 / 자바스크립트] 겹치는 선분의 길이(코딩테스트 입문/ level 0)
청량리 물냉면
청량리 물냉면
프로그래밍 공부를 하고 있습니다. 공부 내용 정리 겸 정보 공유를 목적으로 합니다.
    반응형
  • 청량리 물냉면
    노력중인 블로그
    청량리 물냉면
  • 전체
    오늘
    어제
    • 분류 전체보기 (505)
      • 프로그래밍 (41)
        • Programming (1)
        • C | C++ (6)
        • Java (28)
        • Python (5)
      • 웹 프로그래밍 (108)
        • HTML | CSS (5)
        • JavaScript | TypeScript (41)
        • React (25)
        • Vue.js (0)
        • Next.js (18)
        • Spring & Spring Boot (13)
        • JSP & Servlet (1)
        • DB (4)
      • 웹 프로젝트 (77)
        • 웹 프로젝트 (22)
        • 🥨스낵몰 (3)
        • 👨‍👨‍👧‍👧소셜 가계부 (26)
        • 🌜꿈 일기장 (11)
        • 🔮포트폴리오 사이트 (11)
        • 🏃‍♂️팀 프로젝트: 일정관리 프로그램 (0)
        • 📈팀 프로젝트: AI기반 주식 분석 플랫폼 (0)
        • 😺Just Meow It: 조언 사이트 (2)
        • 📕Workly: 교대근무 다이어리 (1)
      • 앱 프로그래밍 (26)
        • Flutter (24)
        • Kotlin (2)
      • Problem Solving (166)
        • 백준 (52)
        • 프로그래머스 (79)
        • SWEA (29)
      • Computer Science (40)
        • 알고리즘 (14)
        • 컴퓨터 네트워크 (18)
        • 이산수학 (8)
      • Developer (47)
        • 후기 (4)
        • 자료정리 (4)
        • 취업 | 취준 (9)
        • SSAFY (1)
        • 웹개발 교육 프로그램 (9)
        • TIL (20)
  • 블로그 메뉴

    • 홈
    • Github
  • 공지사항

    • 프로그래밍 공부 중😊
  • 인기 글

  • 태그

    클론 프로젝트
    mysql
    ZeroCho
    Jiraynor Programming
    d3
    bfs
    알고리즘
    Next.js
    Til
    리액트
    자바
    파이썬
    포트폴리오
    뉴렉처
    프로그래머스
    강의내용정리
    프로젝트
    타입스크립트
    spring boot
    SWEA
    AWS
    웹사이트
    자바스크립트
    컴퓨터네트워크
    구현
    백준
    React
    플러터
    블로그 제작
    공식문서
  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
청량리 물냉면
[프로그래머스 | 파이썬 / 자바스크립트] [3차] 파일명 정렬(2018 KAKAO BLIND RECRUITMENT / level 2)
상단으로

티스토리툴바