[메서드][Array.prototype.sort()]자바스크립트 정렬함수 sort()

jaemin·2020년 9월 18일
2

자바스크립트

목록 보기
8/12
post-thumbnail

Array.prototype.sort()

sort() 메서드는 배열의 요소를 적절한 위치에 정렬한 후 그 배열을 반환한다.
기본 정렬 순서는 문자열의 유니코드 코드 포인트를 따른다.

const months = ['March', 'Jan', 'Feb', 'Dec'];
months.sort();
console.log(months);
// Array ["Dec", "Feb", "Jan", "March"]

const array1 = [1, 30, 4, 21, 100000];
array1.sort();
console.log(array1);
// Array [1, 100000, 21, 30, 4]

구문

arr.sort([compareFunction])

매개변수

compareFunction
정렬 순서를 정의하는 함수이다. 생략하면 배열은 각 요소의 문자열 변환에 따라 각 문자의 유니 코드 코드포인트 값에 따라 정렬된다.

반환 값

복사본이 만들어지는 것이 아니라 원래의 배열이 정렬된다.

문자 정렬 방법

let arr = ['ddd', 'ccc', 'aaa', 'bbb'];

arr.sort();
console.log(arr); // ['aaa', 'bbb', 'ccc', 'ddd']

숫자 오름차순 정렬 방법

sort()는 문자를 정렬하는 방법이므로 콜백함수를 사용해야 한다.

let arr = [1, 111, 4, 222, 10, 3];

arr.sort(function (a, b) {
  return a - b;
});
console.log(arr); // [1, 3, 4, 10, 111, 222]

여기서 매개함수가 어떻게 작동하는 건지 이해가 되지 않는다.
어떤 방식으로 동작하는지 알아보자.

compareFunction

compare 함수의 형식은 다음과 같다.

  function compare(a, b) {
    if (a가 b보다 작다면) {
      return -1;
    }
    if (a가 b보다 크다면) {
      return 1;
    }
    return 0; // a=b라면
  }

compareFunction이 제공되는 배열 요소는 compare 함수의 반환 값에 따라 정렬된다.
반환 값이 -1이라면 정렬 순서를 바꾸지않는다.(오름차순으로 정렬을 원할 경우)
반환 값이 1이라면 큰 수인 a가 먼저 나온 것이므로 a와 b의 순서를 바꿔 정렬한다.
a와 b가 같은 경우, 정렬 순서를 바꿀 필요가 없다.

여기에서 헷갈렸던 점이 있다.
만약 배열 [2, 1, 4, 5, 3, 6]이 있다고 칠 떄,
[2, 1], [4, 5], [3, 6]을 compare 함수가 비교하여 값을 내놓는다면 결과는
[1, 2, 4, 5, 3, 6]이 될 것이다. 이 같은 방법으론 오름차순 정렬을 할 수 없는데 실제로는 어떻게 동작하는 걸까?

이에 대한 답 :
우선 [20, 10, 9,8,7,6,5,4,3,2,1]의 배열에서 a-b라는 연산을 모두 한 다음
그 결과값으로 정렬하는 것이 결코 아니다.
뭐하러 굳이 뺄셈을 하고 그 값으로 또 정렬할까?

자바스크립트의 정확한 알고리즘은 아니지만 쉽게 정렬 알고리즘을 설명하면 이렇다.

(a,b) 형식으로 지정한 두 인자를 차례로 비교한다.

우선 배열 numbers[0]과 numbers[1] 즉, 20과 10을 비교해 보자
20-10 = 10
결과값이 10 즉, 양수이다.
sort함수에 sortNumber(a,b)의 return 값으로 양수 10을 전달한다.
그럼 sort함수가 양수값을 전달받고 배열의 순서를 바꾸어 버린다.
(정확하게 말하면 두 배열 안에 든 값을 교체)
그럼 배열이 [10, 20, 9,8,7,6,5,4,3,2,1] 이렇게 바뀐다.

그 다음 numbers[0]과 numbers[2] 즉 10과 9를 비교합니다. 10 - 9 = 1 >0, 양수이다.
결과값이 양수이므로 또 10과 9의 순서를 바꾼다.
이런 식으로 계속 두 인자를 비교해서 결과값이 양수가 나오면 순서를 바꾸고,
음수가 나오면 순서를 그대로 유지하는 겁니다.

배열이 바뀌어가는 순서를 보면 이해하기 쉽다.

[(20), (10), 9,8,7,6,5,4,3,2,1] 20-10 = 10, 즉 양수이므로 순서바뀜! ()는 비교되는 인자값.
[(10), 20, (9),8,7,6,5,4,3,2,1] 10 - 9 = 1 또 양수, 순서 바뀜.
[(9), 20, 10, (8),7,6,5,4,3,2,1] 반복...
[(8), 20, 10, 9,(7)...]
...
[(2). 20, 10...3, (1)]
[(1), 20, 10...]

그럼 배열 내에서 가장 작은 값 1이 찾아진다.

[1, 20, 10, 9,8,7,6,5,4,3,2]

1의 순서는 바뀌지 않는다. 1-2 = -1
즉 결과값이 음수이기 때문이다.

그 다음은 두번째 배열 차례이다.
20 - 10 = 10 > 0 이므로 순서를 또 바꾼다.

[1, (20), (10), 9,8,7,6,5,4,3,2][1, (10), 20, (9), 8...]
[1, (9), 20, 10, (8)...]

이런 식으로 반복하다 보면 두번째로 작은 값 2도 찾게 된다.

....
[1, 2, 20, 10, 9,8,7,6,5,4,3]

그럼 다음은 세번째...
이렇게 지루하게 반복하면 결국 정렬이 된다.

물론 실제 자바스크립트에서는 비교하는 순서가 다르다.
다른 알고리즘을 쓰기 때문이다.

이렇게 차례차례 비교해 나가면 인간이 이해하기는 쉽지만
연산량이 기하급수적으로 늘어나기 때문에 다른 정렬 알고리즘을 쓰는 것이다.

실제로는
[20, 10, 9,8,7,6,5,4,3,2,1]
배열의 양쪽 끝부터 비교하고 (20, 1),
그 다음 배열의 가운데 값을 차례로 비교해 나간다. (1,6)
디버깅해 보시면 쉽게 알 수 있다.

숫자 내림차순 정렬

숫자 내림차순 정렬은 오름차순에서 약간의 변화만 주면 된다.
앞서, compareFunction의 반환 값에 따라 정렬된다고 했다.
오름차순의 경우, compareFunction(a, b) 반환 값을 a - b로 주었는데, 이 값이 음수면 a가 작으므로 그대로 정렬했다.
그렇다면, 내림차순의 경우 return 값을 b - a로 줘보자.
b - a가 음수 값으로 나오면 그대로 정렬된다. a가 더 크므로 내림차순 정렬이 된다.

예제로 보면,

let arr = [1, 111, 4, 222, 10, 3];

arr.sort(function (a, b) {
  return b - a;
});
console.log(arr); // [222, 111, 10, 4, 3, 1]

Object 정렬

var student = {
  {name : "Andrew", age : 21},
  {name : "Leo", age : 25},
  {name : "Gabreiel", age : 19},
  {name : "Amy", age : 20},
  {name : "David", age : 26},
  {name : "Bryan", age : 19},
}

student.sort(function(a, b {
  return a.name < b.name ? -1 : a.name > b.name ? 1: 0;
}));

삼항 조건 연산자를 사용했다.
a와 b의 이름의 크기를 비교해 반환 값이 -1이면 출력하고 거짓이라면 다시 a.name > b.name를 비교한다.
이런 방법으로 정렬할 수 있다.

삼항 조건 연산자가 어렵다면 if문으로 변환할 수도 있다. 삼항 조건 연산자는 항상 if문과 변환이 가능하다.

var student = {
  {name : "Andrew", age : 21},
  {name : "Leo", age : 25},
  {name : "Gabreiel", age : 19},
  {name : "Amy", age : 20},
  {name : "David", age : 26},
  {name : "Bryan", age : 19},
}

student.sort(function(a, b) {
  if(a.name < b.name) {
    return -1;
  } else ( a.name > b.name) {
    retrun 1;
  }
  return 0;
  }
);
profile
프론트엔드 개발자가 되기 위해 공부 중입니다.

0개의 댓글