본문 바로가기
dev/javascript

[javascript] 자바스크립트 배열 정렬 (array sort)

by 최연탄 2023. 5. 4.
728x90
반응형

참고: https://www.javascripttutorial.net/javascript-array-sort/

이 포스트에서는 JavaScript Array의 sort() 메소드로 숫자의 배열, 문자열의 배열, 객체의 배열을 정렬하는 방법을 알아보겠습니다.

JavaScript Array sort() 메소드

sort() 메소드를 사용하면 배열의 요소를 알맞은 자리에 정렬할 수 있습니다. sort() 메소드는 정렬된 배열을 리턴하기도 하지만 원본 배열의 요소 위치도 변경합니다.

sort() 메소드는 기본적으로 작은 값 부터 큰 값 까지 오름차순으로 정렬하고 이 때 요소를 문자열로 캐스팅여 문자열 비교를 통해 순서를 결정합니다.

다음의 예제를 확인해 보겠습니다:

let numbers = [0, 1, 2, 3, 10, 20, 30];
numbers.sort();

console.log(numbers);

위의 예제에서 sort() 메소드는 2 앞에 10을 배치했습니다. 문자열 비교 시 "10"은 "2" 보다 작기 때문입니다.

이 문제를 해결하려면 비교 함수를 sort() 메소드의 매개변수로 전달해야 합니다. 이렇게 하면 sort() 메소드는 비교 함수를 사용하여 요소의 순서를 정하게 됩니다.

다음은 sort() 메소드의 문법입니다:

array.sort(comparefunction);

sort() 메소드는 매개변수로 배열의 요소를 두 개씩 비교하는 함수를 옵셔널하게 받습니다. 비교 함수를 생략한다면 sort() 메소드는 위에서 언급한 요소의 유니코드 값을 기준으로 정렬하게 됩니다.

sort() 메소드의 비교 함수는 배열의 요소 중 두 개의 값을 전달하고 리턴 값으로 정렬 순서를 결정하는 값을 반환합니다. 다음은 비교 함수의 문법을 보여줍니다:

function compare(a, b) {
  // ...
}

compare() 함수는 두 개의 인자 a, b를 전달합니다. sort() 메소드는 다음과 같이 compare() 함수의 리턴 값을 바탕으로 배열의 요소를 정렬합니다:

  1. 만약 compare(a, b) 리턴 값이 0 보다 작으면, sort() 메소드는 a를 b 보다 낮은 인덱스에 위치시킵니다. 즉, a를 앞에 둡니다.
  2. compare(a, b) 리턴 값이 0 보다 크면, sort() 메소드는 b를 a 보다 낮은 인덱스에 위치시킵니다. 즉, b가 앞에 위치합니다.
  3. compare(a, b) 결과가 0 이면, sort() 메소드는 a와 b가 같다고 판단하고 그대로 놔둡니다.

숫자 정렬 문제를 해결하기 위해 다음과 같은 코드를 사용할 수 있습니다:

const numbers = [0, 1, 2, 3, 10, 20, 30];

numbers.sort(function (a, b) {
    if(a > b) return 1;
    if(a < b) return -1;
    return 0;
});

console.log(numbers);

또는 화살표 함수 구문을 사용하여 비교 함수를 정의할 수도 있습니다:

const numbers = [0, 1, 2, 3, 10, 20, 30];

numbers.sort((a, b) => {
    if(a > b) return 1;
    if(a < b) return -1;
    return 0;
});

console.log(numbers);

그리고 다음은 숫자 배열 정렬의 가장 간단한 버전입니다:

const numbers = [0, 1, 2, 3, 10, 20, 30];

numbers.sort((a, b) => a - b);

console.log(numbers);

문자열 배열의 정렬

다음과 같이 animals 라는 이름의 문자열 배열이 있다고 가정해보겠습니다:

const animals = [
    'cat', 'dog', 'elephant', 'bee', 'ant'
];

animals 배열의 요소를 알파벳 오름차순으로 정렬하려면 다음 예제와 같이 그냥 sort() 메소드에 매개변수를 주지 않고 사용하면 됩니다:

const animals = [
    'cat', 'dog', 'elephant', 'bee', 'ant'
];

animals.sort();

console.log(animals);

animals 배열을 내림차순으로 정렬하려면 다음 예제와 같이 sort() 메소드의 비교 함수 로직을 바꿔야 합니다.

const animals = [
    'cat', 'dog', 'elephant', 'bee', 'ant'
];

animals.sort((a, b) => {
    if (a > b) return -1;
    if (a < b) return 1;
    return 0;
});

console.log(animals);

다음과 같이 대소문자가 모두 있는 요소를 가진 배열이 있다고 가정해보겠습니다:

const mixedCaseAnimals = [
    'Cat', 'dog', 'Elephant', 'bee', 'ant'
];

이 배열을 알파벳 순서로 정렬하려면 모든 요소를 대문자나 소문자로 동일하게 변환한 후 비교하는 함수를 만들어야합니다. 다음은 모든 요소를 대문자로 변환한 후 비교하는 예제입니다:

const mixedCaseAnimals = [
    'Cat', 'dog', 'Elephant', 'bee', 'ant'
];

mixedCaseAnimals.sort(function (a, b) {
    const x = a.toUpperCase();
    const y = b.toUpperCase();

    return x == y ? 0 : x > y ? 1 : -1;
});

console.log(mixedCaseAnimals);

non-ASCII 문자로 이루어진 배열 정렬

sort() 메소드는 ASCII 문자로 이루어진 배열을 정렬하는데 문제가 없습니다. 그러나 요소가 non-ASCII로 이루어져 있다면 sort() 메소드는 올바로 작동하지 않습니다. 예를 들면:

const animaux = ['zèbre', 'abeille', 'écureuil', 'chat'];

animaux.sort();

console.log(animaux);

보다시피 écureuil 문자열은 zèbre 문자열의 앞에 오지 않았습니다.

이를 해결하기 위해 String 객체를 특정한 로케일에 맞춰 비교하는 localeCompare() 메소드를 사용해야합니다.

animaux.sort(function (a, b) {
    return a.localeCompare(b);
});

console.log(animaux);

이제서야 animaux 배열이 올바르게 정렬됐습니다.

숫자 배열 정렬

다음과 같이 scores 라는 이름의 숫자 배열이 있다고 가정해보겠습니다:

const scores = [
    9, 80, 10, 20, 5, 70
];

숫자 배열을 올바르게 정렬하려면 두 개의 숫자를 비교하는 사용자 정의 비교 함수를 전달해야 합니다.

다음은 scores 배열을 숫자 오름차순으로 정렬하는 예제입니다:

const scores = [
    9, 80, 10, 20, 5, 70
];

scores.sort((a, b) => a - b);

console.log(scores);

위 배열을 내림차순으로 정렬하려면 다음의 예제 처럼 그냥 비교 로직을 반대로 바꾸면 됩니다:

const scores = [
    9, 80, 10, 20, 5, 70
];

scores.sort((a, b) => b - a);

console.log(scores);

객체의 배열을 특정 속성으로 정렬

다음의 배열은 employees 라는 이름의 객체 배열입니다. 각각의 요소는 name, salary, hireDate 세 개의 속성을 가지고 있습니다:

const employees = [
    {name: 'John', salary: 90000, hireDate: "July 1, 2010"},
    {name: 'David', salary: 75000, hireDate: "August 15, 2009"},
    {name: 'Ana', salary: 80000, hireDate: "December 12, 2011"}
];

객체 배열을 숫자 속성으로 정렬

다음은 employees 배열을 salary 속성을 기준으로 오름차순 정렬한 예제입니다.

employees.sort(function (x, y) {
    return x.salary - y.salary;
});

console.table(employees);

이는 간단하게 배열을 숫자 오름차순으로 정렬한 예제입니다. 이전의 비교 함수와 다른 점은 두 개 객체의 salary 속성을 비교한 것 뿐입니다.

객체 배열을 문자열 속성으로 정렬

employees 배열을 name 속성으로 대소문자 구분 없이 정렬하려면 다음과 같이 비교 함수에 대소문자 구분 없이 비교하는 로직을 구현하면 됩니다.

employees.sort(function (x, y) {
    const a = x.name.toUpperCase();
    const b = y.name.toUpperCase();
    return a == b ? 0 : a > b ? 1 : -1;
});

console.table(employees);

Date 속성으로 객체 배열 정렬

각 직원의 고용 날짜를 기준으로 직원을 정렬한다고 가정해보겠습니다.

고용 날짜 데이터는 employee 객체의 hireDate 속성에 저장됩니다. 이는 날짜를 나타내는 문자열일 뿐 Date 객체가 아닙니다.

따라서 고용 날짜별로 직원을 정렬하려면 먼저 날짜 문자열에서 Date 객체를 만든 다음 두 날짜를 비교해야 합니다. 이는 두 개의 숫자를 비교하는 것과 동일합니다.

다음 예제를 보겠습니다:

employees.sort(function (x, y) {
    const a = new Date(x.hireDate);
    const b = new Date(y.hireDate);
    return a - b;
});

console.table(employees);

JavaScript Array sort() 메소드 최적화

사실 sort() 메소드는 각각의 요소에 대하여 비교 함수를 여러번 호출합니다.

강의 이름 길이 순서로 정렬하는 다음의 예를 보겠습니다:

const rivers = ['Nile', 'Amazon', 'Congo', 'Mississippi', 'Rio-Grande'];

rivers.sort(function (a, b) {
    console.log(a, b);
    return a.length - b.length;
});

작동 방식:

  1. 먼저 유명한 강 이름으로 구성된 rivers 배열을 선언합니다.
  2. sort() 메소드를 사용하여 요소의 길이를 기준으로 rivers 배열을 정렬합니다. sort() 메소드가 비교 함수를 호출할 때 마다 rivers 배열의 요소를 출력합니다.

위의 출력에서 볼 수 있듯이 각 요소는 여러 번 비교됐습니다.

만일 배열의 요소가 크게 증가한다면 잠재적 성능은 낮아질 것 입니다.

그렇다고 비교 함수가 실행되는 횟수를 줄일 수는 없습니다. 하지만 비교가 수행해야 하는 작업을 줄일 수는 있습니다. 이 기술을 Schwartzian Transform이라고 합니다.

이를 구현하려면 다음 단계를 수행합니다:

  1. 먼저 map() 메소드를 사용하여 실제 값을 임시 배열로 추출합니다.
  2. 이미 비교한  요소로 임시 배열을 정렬합니다.
  3. 임시 배열을 탐색하여 올바른 순서의 배열을 얻습니다.

다음의 예를 보겠습니다:

const lengths = rivers.map(function (e, i) {
    return {index: i, value: e.length};
});

lengths.sort(function (a, b) {
    return +(a.value > b.value) || +(a.value === b.value) - 1;
});

const sortedRivers = lengths.map(function (e) {
    return rivers[e.index];
});

console.log(sortedRivers);

정리

이 포스트에서는 JavaScript Array의 sort() 메소드를 사용하여 문자열, 숫자, 날짜, 객체의 배열을 정렬하는 방법을 알아봤습니다.

관련 글

자바스크립트 배열 랜덤으로 섞기 (shuffle)

반응형

댓글