알고보면 어려운 sort()..

개발.log·2021년 10월 10일
0

주어진 숫자 배열에서, 0을 배열의 마지막쪽으로 이동시켜주세요.
원래 있던 숫자의 순서는 바꾸지 말아주세요.
(새로운 배열을 생성해서는 안 됩니다.)
Input: [0,1,0,3,12]
Output: [1,3,12,0,0]

현생에 치여 코드카타를 멀리하던 중, 용현님이 이 문제 풀었냐고 물어보셨다.

문제를 딱 보자마자 떠올린 방법은
1. sort로 정렬한 후,
2. for문으로 요소를 하나씩 검사하여 0을 마주치면 count++로 변수에 저장한다.
3.맨앞의 숫자를 count의 숫자만큼 unshift 해주고,
4.push로 count 숫자만큼 붙인다..

오,,,,,듣기만해도 구린코드 🙊
머리를 싸매던 도중, 용현님의 답을 먼저 보게됐는데,

const moveZeroes = nums => {
return nums.sort((a, b) => (a === 0) - (b === 0))
}

와우 유레카! 단 세줄로 끝나는거였다.
못풀었으니까 정답을 보고 이해하는 방향으로 전환하고, sort에 대해 자세히 알아보았다.

sort를 대할 때, array.sort(a,b)=>return a-b 는 오름차순, b-a는 내림차순이라는걸 알고는 있었지만 a,b가 뭔지 정확하게 몰랐다.
내가 갖고 있는 데이터 중에서 price를 console을 찍으며 알아봤는데,

  “goods”: [
    {  
      “price”: 59000,
      “review_count”: 0,
      “colors”: [“red”, “green”, “gray”]
    },
    {
      “price”: 39000,
      “review_count”: 0,
      “colors”: [“white”]
    },
    {
    
      “review_count”: 0,
      “colors”: [“black”]
    },
    {
    
      “review_count”: 3,
      “colors”: [“white”]
    },
    {
  	  “price”: 39000,
      “review_count”: 2,
      “colors”: [“white”]
    },
    {
       “price”: 45000,
      “review_count”: 4,
      “colors”: [“black”]
    },
    {
	   “price”: 99000,
      “review_count”: 6,
      “colors”: [“white”]
    },
    {
 	   “price”: 42000,
      “review_count”: 1,
      “colors”: [“white”]
    },
    {
  	
      “review_count”: 2,
      “colors”: [“green”]
    },
    {
      “price”: 39000,
      “review_count”: 0,
      “colors”: [“white”]
    }
  ]
}

이런식으로 나왔다.a가 앞의 요소, b가 뒤의 요소라고 생각했는데, 전혀 아니였다! 어떤분의 블로그를 참고하자면,

여기서 헷갈릴만한 것 하나가 a와 b입니다. sort((a, b) => b - a) 라는 소스코드와 [1, 2, 3]이라는 배열이 있을 때, 첫 루프로 a에 2가 들어오고 b에 1이 들어옵니다. 즉, a, b의 알파벳 순서와는 반대로 들어옵니다. 이게 헷갈리신다면 sort((next, prev) => prev - next)와 같은 형식으로 사용하는 것도 추천드립니다.

이렇다고한다! 찍힌 콘솔로 알아보자면 2번째 1번째 비교->자리가 바뀐다면->다시 2,1비교 ->다음으로 3,2비교 이런식인것 같다.

다시 블로그글,

1 or 0 or -1 / 단, 변경은 -1에서만 일어난다
[compareFunction]을 작성할 때는 어떤 값을 반환하는지가 중요 합니다. 숫자 값을 반환해야 하는데 총 3가지 경우로 나눌 수 있습니다.
0보다 크다
0이다
0보다 작다
0을 기준으로 3가지 케이스로 나뉩니다.
매개변수로 a, b를 받았고 반환 값이 0보다 큰 경우에는 만일 [a, b]의 값이 들어왔다면, 그대로 [a, b]가 됩니다. a가 먼저옵니다.
매개변수로 a, b를 받았고 반환 값이 0인 경우에는 만일 [a, b]의 값이 들어왔다면, 그대로 [a, b]가 됩니다. a와 b의 위치를 그대로 둡니다.
매개변수로 a, b를 받았고 반환 값이 0보다 작은 경우에 [a, b]의 값이 들어왔다면, b가 먼저 오게 됩니다. [b, a]가 되는 겁니다.
그래서 숫자를 정렬하는 sort 함수를 작성한다할 때, 예를들어 [1, 2, 3, 4, 5]라는 배열이 있다고 할 때 정렬 시 모든 엘리먼트가 순서대로여서 변화가 없다고 가정하면 1, 2, 3, 4 라는 값이 차례로 a로 들어갈 것이고, 2, 3, 4, 5라는 값이 차례로 b로 들어갈 것입니다. 쌍으로 묶어서 보면 [2, 1], [3, 2], [4, 3], [5, 4]의 값이 차례로 a와 b에 들어갑니다.
그런데 일반적인 경우에는 정렬은 하는 도중에 내부의 값들이 변하기 때문에 a, b에 실제로는 우리가 정렬하면서 바뀌게 된 값들이 들어갈 것입니다. 만일, 새로 들어온 값이 더 크다면 바꾸게 하는 [compareFunction]을 작성하고 싶다면 어떻게 해야 할까요?
위에 설명했던 경우의 수를 잘 생각하면 됩니다. 뒤에 들어온게 크면? 바꾸기. 바꿀때는 -1을 리턴하면 되겠죠?

다시 용현님의 코드로 돌아가서

const moveZeroes = nums => {
return nums.sort((a, b) => (a === 0) - (b === 0))
}

a===0 b===0 이 조건은 뭘까?
용현님이 블로그에 잘 설명해 놓았다.😏

a===0, b===0이라는 조건을 통해 값이 0인경우 true가 되게 하여 0이 아닌 1의 값을 가질 수 있도록 해주었고 또한 이 조건 덕분에 0이 아닌 값들은 모두 false가 되어 -1에 해당하는 값을 갖게 되었다. 이를 이용하여 0을 맨 뒤쪽으로 모두 이동시킬 수 있었다.

sort에 대해서 깊게 생각해보지 않고, 무작정 적용했었는데 위에 잘 정리된 블로그들을 보니 작동방식이 조금 이해가 갔다.
언뜻보면 쉬운문제 같았는데 깊게 들어가니까 어렵다. 코드가 어떻게 작동하는지 알고 사용하는게 중요 할 것 같다.

참고자료 :
sort 함수에 대한 잡지식
용현님 블로그

profile
Think Big Aim High Act Now

0개의 댓글