의 동작 Array#sort
과 비교기를 명확히하기 위해 시작 프로그래밍 과정에서 배운 이 순진한 삽입 정렬을 고려하십시오 .
const sort = arr => {
for (let i = 1; i < arr.length; i++) {
for (let j = i; j && arr[j-1] > arr[j]; j--) {
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}
}
};
const array = [3, 0, 4, 5, 2, 2, 2, 1, 2, 2, 0];
sort(array);
console.log("" + array);
알고리즘으로 삽입 정렬의 선택을 무시하고 하드 코딩 된 비교기 : arr[j-1] > arr[j]
. 여기에는 토론과 관련된 두 가지 문제가 있습니다.
>
연산자는 배열 요소하지만 객체가 응답하지 않는 등의 정렬 할 수있는 여러 가지의 쌍 호출 >
(우리가 사용 된 경우 같은 사실이 될 것입니다 합리적인 방법으로 -
).
- 숫자로 작업하는 경우에도 여기에서 구워진 오름차순 정렬 이외의 다른 배열을 원할 때가 있습니다.
comparefn
익숙한 인수를 추가하여 이러한 문제를 해결할 수 있습니다 .
const sort = (arr, comparefn) => {
for (let i = 1; i < arr.length; i++) {
for (let j = i; j && comparefn(arr[j-1], arr[j]) > 0; j--) {
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}
}
};
const array = [3, 0, 4, 5, 2, 2, 2, 1, 2, 2, 0];
sort(array, (a, b) => a - b);
console.log("" + array);
sort(array, (a, b) => b - a);
console.log("" + array);
const objArray = [{id: "c"}, {id: "a"}, {id: "d"}, {id: "b"}];
sort(objArray, (a, b) => a.id.localeCompare(b.id));
console.log(JSON.stringify(objArray, null, 2));
이제 순진한 정렬 루틴이 일반화되었습니다. 이 콜백이 언제 호출되었는지 정확히 알 수 있으며 첫 번째 우려 사항에 답할 수 있습니다.
정렬 과정에서 배열 정렬 콜백 함수가 여러 번 호출됩니까? 그렇다면 매번 함수에 어떤 두 숫자가 전달되는지 알고 싶습니다.
아래 코드를 실행하면 함수가 여러 번 호출되고 console.log
어떤 숫자가 전달되었는지 확인할 수 있습니다 .
const sort = (arr, comparefn) => {
for (let i = 1; i < arr.length; i++) {
for (let j = i; j && comparefn(arr[j-1], arr[j]) > 0; j--) {
[arr[j], arr[j-1]] = [arr[j-1], arr[j]];
}
}
};
console.log("on our version:");
const array = [3, 0, 4, 5];
sort(array, (a, b) => console.log(a, b) || (a - b));
console.log("" + array);
console.log("on the builtin:");
console.log("" +
[3, 0, 4, 5].sort((a, b) => console.log(a, b) || (a - b))
);
물어:
두 세트의 숫자는 서로를 기준으로 어떻게 정렬됩니까?
용어를 정확하게에 a
와 b
없는 세트 (그들이있는 거 번호 귀하의 예제에서) 배열의 라고요 객체 - 숫자.
진실은 구현에 따라 다르기 때문에 정렬 방법 은 중요하지 않습니다 . 삽입 정렬과 다른 정렬 알고리즘을 사용했다면 비교기가 다른 숫자 쌍에서 호출 될 수 있지만 정렬 호출이 끝날 때 JS 프로그래머에게 중요한 것은 결과 배열이 다음에 따라 정렬된다는 것입니다. comparator, comparator는 당신이 언급 한 계약을 준수하는 값을 반환한다고 가정합니다 (<0 when a < b
, 0 when a === b
and> 0 when a > b
).
내 사양을 위반하지 않는 한 내 정렬의 구현을 자유롭게 변경할 수있는 것과 같은 의미에서 ECMAScript의 구현은 언어 사양 의 범위 내에서 정렬 구현을 자유롭게 선택할 수 있으므로 Array#sort
다른 비교기 호출을 생성 할 가능성이 높습니다. 다른 엔진에서. 논리가 특정 일련의 비교에 의존하는 코드를 작성하지 않을 것입니다 (비교기가 처음에 부작용을 생성해서는 안 됨).
예를 들어 V8 엔진 (작성 당시)은 배열이 미리 계산 된 요소 수보다 클 때 Timsort를 호출 하고 작은 배열 청크에 이진 삽입 정렬 을 사용합니다 . 그러나 그것은 불안정하고 다른 인수 순서와 비교기에 호출을 줄 가능성이있는 quicksort 를 사용했습니다 .
다른 정렬 구현은 비교기 함수의 반환 값을 다르게 사용하기 때문에 비교기가 계약을 준수하지 않을 때 놀라운 동작이 발생할 수 있습니다. 예제는 이 스레드 를 참조하십시오 .