복's

[ Programmers - LV2 ] [3차] 파일명 정렬 본문

알고리즘/Programmers

[ Programmers - LV2 ] [3차] 파일명 정렬

나복이 2024. 8. 25. 19:35
728x90

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

 

프로그래머스

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

programmers.co.kr

 

 

단순히 주어진 조건으로 파일명을 정렬하는 문제이다.

나는 주로 정렬 문제는 구현 되어있는 sort() 사용하거나 필요에 따라서 인터페이스 Compartor 를 구현 해서 풀이 햐였는데 오늘은 뭔가 색다른 풀이를 원하고 있었고, 조금 더 객체지향(?)적인 코드를 짜고 싶어졌다.

 

결국 과하다는 생각에 코드를 조금 되돌리기는 했지만 이번 풀이 덕분에 조금은 틀에서 벗어난 기분을 느껴서 좋았다.


📌 분석

  • 파일 구성: HEADER - BODY(NUM) - TAIL
  • 정렬 조건:
    1. HEADER(1차): 대소문자 관계 없이 문자열 비교
    2. BODY(2차): 숫자 크기 비교
  • 위 조건을 생각하면 TAIL 은 정렬에 관여하지 않는다.

그 밖에 문자열 값에 대한 조그마한 조건들이 있지만 크게 신경쓰지 않아도 문제는 풀린다.


📌 최종 코드 - Java

결국 정렬 문제기 때문에 중요한 부분은 정렬 코드다.

조건 1은 Header 기준으로 비교하고, 두 Header 가 똑같다면 뒤의 Body(num) 으로 비교해야 한다.

작은 조건중 하나는 모든게 같다면 입력 값 순서를 유지하는 Stable Sort 를 요구 했는데, 처음에는 for 을 통해서 인덱스를 받아서 sequnce 를 따로 저장해서 유지 하려고 했지만 신경쓸 필요 없었다.

@Override
public int compareTo(File file) {
    int headRes = this.head.compareTo(file.head);

    if(headRes == 0) {
        return this.num - file.num;
    }

    return headRes;
}

 

최종 코드는 아래와 같다.

import java.util.ArrayList;
import java.util.List;

class Solution {
    public String[] solution(String[] files) {
        List<File> fileList = new ArrayList<>();

        for(String file : files) {
            fileList.add(getFile(file));
        }

        fileList.sort(File::compareTo);  // 정의 해놓은 compareTo 기준으로 정렬

        return fileList.stream().map(File::getOrigin).toArray(String[]::new);  // 파일의 원본 이름 기준으로 배열 생성
    }

    public File getFile(String file) {
        int idx = 0;  // file 맨 앞 글자
        String head;
        int num;

        StringBuilder sb = new StringBuilder();

        // HEAD 추출
        while(idx < file.length() && !Character.isDigit(file.charAt(idx))) {
            sb.append(file.charAt(idx++));
        }

        head = sb.toString();
        sb.setLength(0);  // StringBuilder 초기화

        // NUM 추출
        while(idx < file.length() && Character.isDigit(file.charAt(idx))) {
            sb.append(file.charAt(idx++));
        }

        num = Integer.parseInt(sb.toString());
        sb.setLength(0);

        return new File(file, head, num);
    }

    class File implements Comparable<File> {
        String origin;
        String head;
        int num;

        public File(String origin, String head, int num) {
            this.origin = origin;
            this.head = head.toUpperCase();
            this.num = num;
        }

        @Override
        public int compareTo(File file) {
            int headRes = this.head.compareTo(file.head);

            if(headRes == 0) {
                return this.num - file.num;
            }

            return headRes;
        }

        public String getOrigin() {
            return origin;
        }
    }
}

📌 결과

[ 결과 - Java ]


📌 마치며...

객체지향적인 코드라고 했던건 위 코드가 아닌 처음 제출한 코드인데 구조 자체가 완전히 달랐다.

아래와 같이 파일을 구성하는 각 요소들에 대한 인스턴스를 갖고 있는데, 코드를 결국 수정한 이유는 알고리즘 문제 풀이에 적합하지 않았다고 생각이 되어서...

 

매 파일 생성마다 4개의 인스턴스를 생성해서 갖고 있어야 했고, 각 요소(내부 클래스) 의 역할을 나눈만큼 큰 기능이 없었다.

            - HEADER
FILE     - BODY(NUM)
             - TAIL

 

매번 클래스와 그에 상응하는 메타 데이터 생성이 (물론 성능에 큰 영향은 없음) 알고리즘 문제 풀이라는 목적에 부합하지 않다고 생각하였다.

 

하지만 이렇게 풀어도 될까 라는 마음을 갖고 풀어서 그런지 재밋게 문제 풀이를 할 수 있었다.

728x90