[CodeWars] 문자열 내 마음대로 정렬하기

호두파파·2021년 2월 22일
0

알고리즘 연습

목록 보기
4/60
post-thumbnail

문제

Given a string of words (x), you need to return an array of the words, sorted alphabetically by the final character in each.

If two words have the same last letter, they returned array should show them in the order they appeared in the given string.

Test.describe("Basic tests",_=>{
Test.assertSimilar(last('man i need a taxi up to ubud'), ['a', 'need', 'ubud', 'i', 'taxi', 'man', 'to', 'up']);
Test.assertSimilar(last('what time are we climbing up the volcano'), ['time', 'are', 'we', 'the', 'climbing', 'volcano', 'up', 'what']); 
Test.assertSimilar(last('take me to semynak'), ['take', 'me', 'semynak', 'to']); 
Test.assertSimilar(last('massage yes massage yes massage'), ['massage', 'massage', 'massage', 'yes', 'yes']); 
Test.assertSimilar(last('take bintang and a dance please'), ['a', 'and', 'take', 'dance', 'please', 'bintang']); 
})

인자로 주어진 문자열을 공백을 기준으로 배열로 치환하고, 각 단어의 '마지막'글짜를 기준으로 올림 차순으로 정렬해 리턴하는 문제 (응용문제로 n번째 글자를 기준으로 정렬하기도 있다.)


문제풀이

문제는 문자열로 구성된 문자열을 각 단어의 마지막 글자를 기준으로 오름차순 정렬하기 였다.

간단한 sorting 문제인줄 알았지만, 마지막 글자가 같은 문자열이 여럿일 경우, 사전순으로 앞선 문자열이 앞쪽에 위치하여야 하는 조건이 핵심이었다.

우선 JavaScript에서의 sort()함수는 기본적으로 원소들을 문자열로 만든 뒤에, UTF-16코드 유닛 값을 기준으로 순서를 정렬한다. 다시 말해 문자열로 바꾼 뒤에 정렬을 하기 때문에 숫자 정렬에 적합하지 않다.

숫자정렬을 언급한 이유는, n번째 글자(문제의 조건은 마지막)를 정렬하기 때문에, 문자의 ASCII 코드로 비교를 하기 때문이다.

function solution(x) {
    return x.split(' ').sort((a,b) => a.charCodeAt(a.length - 1) - b.charCodeAt(b.length - 1));
}

위 코드는 첫번째 케이스를 통과하지만, 두번째 세번째 케이스는 실패한다.
사전순으로 앞선 문자열이 앞쪽에 위치합니다. 라는 조건을 충족하지 못해서이다.

sort([callback])는 callback에 인자로 fistElement와 secondElement가 들어오며, 연산의 결과가 -1일때만 변경이 일어난다.

예를 들어 [a, b] 배열에서,
a-b 연산이 0보다 큰 경우 변화 x
a-b 연산이 0일 경우 변화 x
a-b 연산이 0보다 작을 경우에만 [b,a]로 스왑된다.

내림차순으로 정렬해야 할 경우 function(a,b) => b-a 로 콜백함수를 작성해주면 된다.

조건을 추가해서 코드를 작성하면

function solution(x) {
  return x.split(' ').sort((a, b) => {
    let first = a.charCodeAt(a.length - 1);
    let second = b.charCodeAt(b.length - 1);
    
    if(first === second)
      return a.localeCompare(b); // a문자를 기준으로 b문자를 위치시키는 메소드.
    else
      return first - second; // sort 함수의 작동원리를 함수 식으로 제공 
  });
}

조건을 추가해, localeCompare() 함수를 사용해 문자열끼리 비교해 처리해주었다.

localeCompare함수는 기준 문자열과 비교했을 때 비교 대상 문자열이 정렬상 전에 오는지, 후에 오는지 혹은 같은 순서에 배치되는지를 알려주는 숫자를 리턴하는 함수다.

하지만 charCodeAt()함수나 localeCompare() 함수 때문인지 처리시간이 길게 나오는 경우가 있어서 좋은 코드를 참조할 수 있었다.

function solution(x) {
    return x.split(' ').sort((a, b) => {
        const first = a[a.length - 1]; // a 문자열의 마지막 글자 
        const second = b[b.length - 1]; //  b 문자열의 마지막 글자
        
        if(first === second)
            return (a > b) - (a < b); // 순서대로 정렬해주는 함수식 
        else
            return (first > second) - (first < second); // sort() 함수 식을 코드로 구현화
    });
}

우수 문제 풀이

function solution(x) {
  return x.split(' ').sort((a, b) => a.charCodeAt(a.length - 1) - b.charCodeAt(b.length - 1));
}
function last (words) {
  return words.split(' ').sort((a, b) => a.slice(-1).localeCompare(b.slice(-1)))
}

배열의 요소를 임의 조작하기 위해서 localeCompare를 활용하면 함수가 유연하게 작성된다는 것 을 깨달은 풀이.

profile
안녕하세요 주니어 프론트엔드 개발자 양윤성입니다.

0개의 댓글