Unique In Order<6 kyu>

jjanmo·2019년 12월 31일
0

Codewars에서 뒹굴기

목록 보기
8/32

문제링크

문제

Implement the function unique_in_order which takes as argument a sequence and returns a list of items without any elements with the same value next to each other and preserving the original order of elements.

For example:

  • uniqueInOrder('AAAABBBCCDAABBB') == ['A', 'B', 'C', 'D', 'A', 'B']
  • uniqueInOrder('ABBCcAD') == ['A', 'B', 'C', 'c', 'A', 'D']
  • uniqueInOrder([1,2,2,3,3]) == [1,2,3]

문제접근

filter() 메소드를 사용해서 같은 것을 제거하고 그 전 요소와 다른 것들만 뽑아서 새로운 배열을 만들면 되지 않을까?

  • 나의 풀이
var uniqueInOrder=function(iterable){
  let pre;	//전 단계의 요소
  if(Array.isArray(iterable)){
    return iterable.filter(function(v,i){
      if(i === 0) {
        pre = v 
        return true;
      }
      else{
        if(pre !== v){
          pre = v;
          return true;
        }
      }
    });
  }//if
  else{
    return iterable.split('').filter(function(v,i){
      if(i === 0) {
        pre = v 
        return true;
      }
      else{
        if(pre !== v){
          pre = v;
          return true;
        }
      }
    });
  }//else
}

위의 생각처럼 풀다보니 문제가 생겼다. iterable 요소들이 숫자로 된 배열일 수 도, 아니면 그냥 문자열 일 수도 있었다. 우선 기본적으로 주어진 매개변수가 배열인지 아닌지를 구분하고 각각에 인덱스 값에 따라서 필터링 하였다. 그런데 뭔가 아쉽다. 너무 길다. 문자열인지 배열인지를 구분하지 말고 하나로 할 수 있는 방법은 없을까?

  • 리팩토링

    리팩토링이란 결과의 변경 없이 코드의 구조를 재조정함'을 뜻한다. 주로 가독성을 높이고 유지보수를 편하게 한다. 버그를 없애거나 새로운 기능을 추가하는 행위는 아니다. 사용자가 보는 외부 화면은 그대로 두면서 내부 논리나 구조를 바꾸고 개선하는 유지보수 행위이다. [참고]

리팩토링이라고 불릴만큼 거창한 것은 아니지만 코드를 좀 더 효율적으로 짧고 가독성이 높게 고치고자 하였다.

  1. filter() 안의 조건을 나눈 이유는 이렇다. pre라는 변수를 선언만 했지 값을 할당 하지 않아서 비교 불가능 상태라고 생각을 했고, 그렇기 때문에 첫번째 루프에 값을 할당을 해줘야 그 다음 루프부터 비교가능한 상태가 될거라고 생각했다. 하지만 이것은 아직 undefined라는 자바스크립트의 값에 대해서 정확히 이해하지 못했기에 나온 코드임을 알게 되었다.

     자바스크립트에서는 undefined 값을 주는 경우
     1. uninitialized variables
     2. non-existing object properties or methods
     3. out of bounds indexes to access array elements
     4. the invocation result of a function that returns nothing 

    pre라는 변수를 사용한다면 굳이 첫번째 루프에서 값을 할당할 필요가 없다. 왜냐하면 이미 선언을 한 순간 undefined라는 값을 갖고 있기 때문에 비교 가능한 상태이다. 그리고 위 문제의 상황을 보면 어차피 첫번째 원소는 무조건 새로운 배열에 포함되기 때문에 무슨값과 비교를 하든 상관이 없다. 비교 할 수 있는 상태만을 위한 것이라면 이미 값이 값이 할당되어있는(undefined) 상태에서도 가능하기 때문에 다시 정확한 값(인덱스 0의 값)을 할당해주는 것은 큰 의미가 없어보인다.
    pre라는 변수를 사용안한다면 이것도 가능하다. undefined 값이 나오는 3번째 경우를 보면 out of bounds indexes array인 경우에 undefined 값을 준다.(index out of bounds는 자바나 C에서는 자주 마주치는 런타임에러이다.) 그래서 viterable[i-1] 을 비교 가능하다. i0 인 경우(첫번째 루프)에는 iterable[-1]이지만 위에서 보았듯이 undefined를 갖기 때문에 비교 가능하고 filter()의 조건에 따라서 새로운 배열의 요소가 된다.

  2. 문자열인 경우는 split('') 메소드를 통해서 문자열을 배열로 전환하는 코드를 따로 적어줘야한다. 아닌 경우는 바로 filter()를 하면 된다. 이 두가지를 합치고 싶었다. 이럴 때 생각할 수 있는 것이 Spread Operator이다. 문자열 혹은 배열의 요소를 ...을 통해서 각각의 요소로 분리 시켜서 놓은 다음에 다시 배열 안에 놓는 방법으로 할 수 있었다. 어제 보았던 그 방법이였다. 하지만 직접 사용해보지 않았기 때문에 어제 보았다한들 사용할 수 없었던 것 같다. 코드로 보면 이렇다. [...iterable].filter()] 이 코드 한 줄로 두 가지를 합칠 수 있었다.

위의 내용을 반영한 코드이다.

  var uniqueInOrder=function(iterable){
    return [...iterable].filter(function(v,i){
          return v !== iterable[i-1];
     	});
 }

Best Solution

앞에서 리팩토링한 풀이와 유사한 풀이 역시 있었지만, 가장 좋은 풀이라고 선정된 풀이는 다른 것이였다.

  function uniqueInOrder(it) {
    var result = [];
    var last;
    for (var i = 0; i < it.length; i++) {
      if (it[i] !== last) {
        result.push(last = it[i]) ;
        /*
        last = it[i];
        result.push(last) 
        */
      }
    }
    return result;
}
  • 주석처리한 부분을 위에 한 줄로 한 번에 쓸 수 도 있다는 것을 처음 알았다. 밑에 처럼 한 줄, 한 줄 분리하여 적는 것이 일반적이여서 저렇게 쓰는 방법에 대해선 신기하였다.( 정확하게 어떤 규칙에 의해서 저렇게 되는 것인지는 아직 잘 모르겠다.)

  • String[index] vs String.charAt[index]
    자바에 익숙하다보니 당연히 문자열에서 문자에 접근하고자 한다면, charAt()을 사용하였다. 위 풀이를 보면 문자열이든 배열이든 같은 방식으로 접근하는 것을 볼 수 있다. 공식문서를 보면 문자열을 string as an array-like object 로 다루어서 인덱스로 바로 접근이 가능하다. [참고] ECMAScript5를 지원할 때만 가능하다고 적혀있다.

결론

undefined에 대한 정확한 개념과 언제 undefined이 나타나는지에 대해서 알 수 있었다. undefined는 봐도 봐도 항상 나타나는 문제인 것 같다. 나중에 따로 정리하는 기회가 만들어야겠다. 또 자바스크립트에서만 가능한, 조금은 느슨하게(?) 문자에 접근이 가능한 방법을 알게 되었다. 한가지 언어를 알면 다른 언어를 배울 때 조금 더 빠르게 접할 수 있지만, 반대로 이미 알고 있는 언어처럼 사용하는 경우도 있다. 좀 더 쉽게 생각할 수 있는 부분에 대해서는 점차 익숙해져야겠다. (단, 이 부분은 맞고 틀리고의 문제는 아니라고 생각한다.)

참고

7 Tips to Handle undefined in JavaScript
stack overflow - string.charAt(x) or string[x]?
Wiki Refactoring

🚀 문제를 풀어나갈 때 생각의 흐름을 정리합니다. 또한 새로운 풀이에 대한 코드를 분석하고 모르는 부분에 대해서 정리합니다. 다른 의견은 언제나 환영합니다. 틀린 내용에 대한 피드백 또한 항상 감사합니다.

profile
눈길을 걸어갈 때 어지럽게 걷지 말기를.

0개의 댓글