본문 바로가기
Javascript

Array.prototype.sort()

by 이도현 2021. 11. 10.

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

 

Array.prototype.sort() - JavaScript | MDN

sort() 메서드는 배열의 요소를 적절한 위치에 정렬한 후 그 배열을 반환합니다. 정렬은 stable sort가 아닐 수 있습니다. 기본 정렬 순서는 문자열의 유니코드 코드 포인트를 따릅니다.

developer.mozilla.org

https://www.w3schools.com/jsref/jsref_sort.asp

 

JavaScript Array sort() Method

W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

www.w3schools.com

sort() 메서드는 배열의 요소를 정렬한 후 그 배열을 반환한다.

기본 정렬 순서는 문자열의 유니코드 코드 포인트를 따른다. 

특히 조심해야하는 부분은 sort()함수를 쓰고 나면 복사본을 만들어서 정렬을 시키는 것이 아니라 원 배열이 정렬 되는 것이라는 점이다. 

 

sort() 메서드를 그냥 사용하면 문자 배열을 정렬할 때는 크게 혼동되는 부분이 없지만, 숫자를 정렬하면 조금 헷갈리는 부분이 생길 수 있다.

다음 예시를 보자.

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

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

숫자배열 정렬이 완료되었는데, 1, 4, 21, 30 .. 이런 순의 숫자 오름차순이 아니라 1, 100000, 21 ... 이런식으로 첫 숫자의 배열을 따르게 된다. 좀 더 명확하게 하기 위해 예시를 하나 더 만들었다. 

const string_array = ['000001', '000030', '000004', '000021', '100000'];
string_array.sort();
console.log(string_array);
//Array ["000001", "000004", "000021", "000030", "100000"]

const number_array = [000001, 000030, 000004, 000021, 100000];
number_array.sort();
console.log(number_array);
//Array [1, 100000, 17, 24, 4]

만약 숫자 오름차순으로 정렬을 하고 싶다면 sort() 메서드를 그냥 사용하는 것은 의미가 없다는 것을 알 수 있다.

그러면 어떻게 숫자 오름차순 정렬을 하는지는 구문과 매개 변수의 사용법을 확인하면 알 수 있다.

 

구문은 다음과 같다.

arr.sort([compareFunction])

매개변수 compareFunction 는 함수로 구성하면 되는데, 다음 설명을 통해 우리가 원하는 방식으로 정렬시킬 수 있다.


설명

 

compareFunction이 제공되지 않으면 요소를 문자열로 변환하고 유니 코드 코드 포인트 순서로 문자열을 비교하여 정렬됩니다. 예를 들어 "바나나"는 "체리"앞에옵니다. 숫자 정렬에서는 9가 80보다 앞에 오지만 숫자는 문자열로 변환되기 때문에 "80"은 유니 코드 순서에서 "9"앞에옵니다.

compareFunction이 제공되면 배열 요소는 compare 함수의 반환 값에 따라 정렬됩니다. a와 b가 비교되는 두 요소라면,

  • compareFunction(a, b)이 0보다 작은 경우 a를 b보다 낮은 색인으로 정렬합니다. 즉, a가 먼저옵니다.
  • compareFunction(a, b)이 0을 반환하면 a와 b를 서로에 대해 변경하지 않고 모든 다른 요소에 대해 정렬합니다. 참고 : ECMAscript 표준은 이러한 동작을 보장하지 않으므로 모든 브라우저(예 : Mozilla 버전은 적어도 2003 년 이후 버전 임)가 이를 존중하지는 않습니다.
  • compareFunction(a, b)이 0보다 큰 경우, b를 a보다 낮은 인덱스로 소트합니다.
  • compareFunction(a, b)은 요소 a와 b의 특정 쌍이 두 개의 인수로 주어질 때 항상 동일한 값을 반환해야합니다. 일치하지 않는 결과가 반환되면 정렬 순서는 정의되지 않습니다.

일반적인 비교 함수 형식은 다음과 같다.

function compare(a, b) {
  if (a is less than b by some ordering criterion) {
    return -1;
  }
  if (a is greater than b by the ordering criterion) {
    return 1;
  }
  // a must be equal to b
  return 0;
}

오름차순의 경우 다음과 같이 빼기를 사용하여 작성할 수도 있다.

function compareNumbers(a, b) {
  return a - b;
}

이 함수를 이용하여 처음의 예제를 다시 정렬해본다.

function compareNumbers(a, b) {
  return a - b;
}

const number_array = [000001, 000030, 000004, 000021, 100000];
number_array.sort(compareNumbers);
console.log(number_array);
//Array [1, 4, 17, 24, 100000]

우리가 원하는 방식으로 오름차순 정렬이 되었다.

내림차순은 단순히 a, b의 위치를 바꿔주는 것만으로 가능하다.

function compareNumbers(a, b) {
  return b - a;
}

const number_array = [000001, 000030, 000004, 000021, 100000];
number_array.sort(compareNumbers);
console.log(number_array);
//Array [100000, 24, 17, 4, 1]

사실 실무에서 이런 숫자배열이나 문자배열을 정렬할 일은 크게 없을 것 같고 실무에서 쓸만한 객체 배열에서 정렬하는 방법의 예시를 가져왔다.

var items = [
  { name: 'Edward', value: 21 },
  { name: 'Sharpe', value: 37 },
  { name: 'And', value: 45 },
  { name: 'The', value: -12 },
  { name: 'Magnetic', value: 13 },
  { name: 'Zeros', value: 37 }
];

// value 기준으로 정렬
items.sort(function (a, b) {
  if (a.value > b.value) {
    return 1;
  }
  if (a.value < b.value) {
    return -1;
  }
  // a must be equal to b
  return 0;
});
console.log(items);
//Array [Object { name: "The", value: -12 }, Object { name: "Magnetic", value: 13 }, Object { name: "Edward", value: 21 }, Object { name: "Sharpe", value: 37 }, Object { name: "Zeros", value: 37 }, Object { name: "And", value: 45 }]

// name 기준으로 정렬
items.sort(function(a, b) {
  var nameA = a.name.toUpperCase(); // ignore upper and lowercase
  var nameB = b.name.toUpperCase(); // ignore upper and lowercase
  if (nameA < nameB) {
    return -1;
  }
  if (nameA > nameB) {
    return 1;
  }

  // 이름이 같을 경우
  return 0;
});
console.log(items);
//Array [Object { name: "And", value: 45 }, Object { name: "Edward", value: 21 }, Object { name: "Magnetic", value: 13 }, Object { name: "Sharpe", value: 37 }, Object { name: "The", value: -12 }, Object { name: "Zeros", value: 37 }]

 

sort() 메서드는 작업 효율을 높혀주고 코드를 깔끔하게 할 수는 있겠지만, 배열내 요소가 여러번 호출될 수 있다는 단점이 있다. 이에 map()을 이용한 정렬을 고려해보라고 한다. 이 방식은 임시배열을 만들어서 실제 정렬에 필요한 값만 뽑아 정렬하고 그 결과를 이용해 다시 정렬하는 방식이다.

// 소트 할 배열
var list = ['Delta', 'alpha', 'CHARLIE', 'bravo'];

// 임시 배열은 위치 및 정렬 값이있는 객체를 보유합니다.
var mapped = list.map(function(el, i) {
  return { index: i, value: el.toLowerCase() };
})
console.log(mapped);
//> Array [Object { index: 0, value: "delta" }, Object { index: 1, value: "alpha" }, Object { index: 2, value: "charlie" }, Object { index: 3, value: "bravo" }]

// 축소 치를 포함한 매핑 된 배열의 소트
mapped.sort(function(a, b) {
  return +(a.value > b.value) || +(a.value === b.value) - 1;
});
console.log(mapped);
//> Array [Object { index: 1, value: "alpha" }, Object { index: 3, value: "bravo" }, Object { index: 2, value: "charlie" }, Object { index: 0, value: "delta" }]


// 결과 순서를 위한 컨테이너
var result = mapped.map(function(el){
  return list[el.index];
});

console.log(result);
//> Array ["alpha", "bravo", "CHARLIE", "Delta"]

 

이외에도 주의할 사항은 더 있지만, 비 ASCII 문자 정렬 같은 문제들은 링크를 참조하면 될 것 같다.