Javascript Sort함수에 대한 잡지식

Jake Seo·2020년 6월 23일
26

jakes-javascript-tips

목록 보기
2/2
post-thumbnail

Javascript SORT 함수의 희한한 정렬

자바스크립트의 sort 함수는 기본적으로 원소들을 문자열로 만든 뒤에, UTF-16 코드 유닛 값을 기준으로 순서를 정렬합니다. 여기서 눈치 채신 분도 있겠지만 문자열로 바꾼 뒤에 정렬을 하기 때문에 숫자 정렬에 적합하지 않습니다.

기본 값은 문자열로 변경 후에 UTF-16 코드 유닛 값을 기준으로 정렬

UTF-16 코드 유닛 값으로 값을 정렬하게 되면, 숫자에 대해 올바른 정렬이 되지 않습니다. 이를테면 [1, 30, 4, 21, 100000];을 정렬한 결과가 [1, 100000, 21, 30, 4]와 같이 나오게 되는 현상이 발생합니다.

이러한 sort 함수의 특징 때문에 우리는 sort 함수에 대한 커스터마이징을 해주어야 합니다.

비교 함수(Compare Function) 작성하기

sort 함수의 기본 문법은 arr.sort([compareFunction]) 입니다. 여기서 우리가 정의해줘야 하는 것은 [compareFunction] 부분입니다.

[compareFunction]은 sort 함수의 콜백함수로 firstElsecondEl이란 인자가 자동으로 들어갑니다. 이 콜백함수의 작성을 생략하면 이전에 설명했듯 문자열로 바뀐 뒤 UTF-16의 코드 유닛 값을 기준으로 정렬이 수행됩니다.

[compareFunction]은 다양한 언어에서 콜백함수로 작성됩니다. 이를테면 Java와 같은 언어에서도 이러한 함수를 작성하는 부분이 있습니다.

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]가 됩니다. ab의 위치를 그대로 둡니다.
  • 매개변수로 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]의 값이 차례로 ab에 들어갑니다.

그런데 일반적인 경우에는 정렬은 하는 도중에 내부의 값들이 변하기 때문에 a, b에 실제로는 우리가 정렬하면서 바뀌게 된 값들이 들어갈 것입니다. 만일, 새로 들어온 값이 더 크다면 바꾸게 하는 [compareFunction]을 작성하고 싶다면 어떻게 해야 할까요?

위에 설명했던 경우의 수를 잘 생각하면 됩니다. 뒤에 들어온게 크면? 바꾸기. 바꿀때는 -1을 리턴하면 되겠죠?

간단하게 삼항연산자로 표현하면 a > b ? -1 : 0 처럼 표현할 수 있겠네요.

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

코드 예제

코드 예제를 만들어 살펴봅시다.

let someNumberArray = [5, 4, 3, 2, 1];
someNumberArray.sort((next, prev) => prev > next ? -1 : 0); // return [1, 2, 3, 4, 5]
// 이전 엘리먼트가 이후 엘리먼트보다 크면 순서를 바꾸기 때문에 결국 오름차순으로 정렬됩니다.

원본도 변경되는 것에 주의!

sort 함수는 원본을 변경하는 함수이기 때문에 매우 주의해야 합니다!

위의 소스코드 이후에 다시 someNumberArray의 상태를 확인해보면, [1, 2, 3, 4, 5]로 바뀌어있는 것을 알 수 있습니다. 원본도 변경하면서 결과를 반환도 하니까 알아두시면 좋을 것 같습니다.

자주 쓰이는 커스터마이징

어찌됐든, sort 함수의 핵심은 비교함수를 작성하는 것이고, 비교함수에서 a(next)b(prev)가 들어오고 무언가 바꾸고 싶을 때 -1을 리턴하는 것! 입니다.

숫자 정렬

숫자를 정렬할 때 사실 위와 같은 삼항연산자도 필요 없다는 사실을 아시나요?

만일, 오름차 순으로 정렬하고 싶다면

arr.sort((a, b) => a - b)와 같이 작성하면 됩니다. b 가 더 클 때만 a - b의 결과로 음수가 나옵니다. 그러면 b 즉, 앞에 있는 값이 더 클 때 변경이 일어나니까 뒤에 있는 큰 값이 다 앞으로 오게 돼서 오름차 순 정렬이 됩니다.

만일, 내림차 순으로 정렬하고 싶다면

arr.sort((a, b) => b-a)와 같이 작성하면 됩니다. a (뒤에 있는 값을 의미)가 더 클 때만 b - a 의 결과로 음수가 나오겠죠? 그러면 결국 뒤에 있는 값이 클 때 변경이 일어나기 때문에, 큰 값은 뒤로 가게 되고 작은 값은 앞으로 오게 돼서 내림차순 정렬이 됩니다.

기타 예제는 https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/sort 에서 보실 수 있습니다. Object와 같은 곳에 응용도 가능합니다.

profile
풀스택 웹개발자로 일하고 있는 Jake Seo입니다. 주로 Jake Seo라는 닉네임을 많이 씁니다. 프론트엔드: Javascript, React 백엔드: Spring Framework에 관심이 있습니다.

7개의 댓글

comment-user-thumbnail
2021년 1월 3일

감사합니다.

답글 달기
comment-user-thumbnail
2021년 4월 2일

감사합니다!

1개의 답글
comment-user-thumbnail
2021년 7월 3일

감사합니다!

답글 달기
comment-user-thumbnail
2021년 7월 4일

감사합니다!

답글 달기
comment-user-thumbnail
2021년 12월 27일

감사합니다~

답글 달기
comment-user-thumbnail
2021년 12월 30일

정렬에 대해서 정리한 자료는 잘보았습니다 하나 의문점이 있어서 댓글을 다는데요
[오름차순 정렬]
arr.sort((a, b) => a - b)와 같이 작성하면 됩니다. b 가 더 클 때만 a - b의 결과로 음수가 나옵니다. 그러면 b 즉, 앞에 있는 값이 더 클 때 변경이 일어나니까 뒤에 있는
[[큰 값이 다 앞으로 오게 돼서]] // 해당 부분
오름차 순 정렬이 됩니다.

위에 표시한 내용이 반대로 적으신게 아닌지해서요 a-b를 해서 앞에 있는 값이 더 크면 변경이 되는데 앞에 있는 값이 더크면 뒤에 있는 작은 값이 앞으로 오게 되서 오름차순 정렬이 되는거 아닌가요?

답글 달기