I'm attempting to create my own sort function (question Async version of sort function in JavaScript). I've taken merge sort function from Rosetta Code and make it async:
// based on: https://rosettacode.org/wiki/Sorting_algorithms/Merge_sort#JavaScript
async function mergeSort(fn, array) {
if (array.length <= 1) {
return array;
}
const mid = Math.floor(array.length / 2),
left = array.slice(0, mid), right = array.slice(mid);
await mergeSort(fn, left)
await mergeSort(fn, right)
let ia = 0, il = 0, ir = 0;
while (il < left.length && ir < right.length) {
array[ia++] = (await fn(left[il], right[ir]) <= 0) ? left[il++] : right[ir++];
}
while (il < left.length) {
array[ia++] = left[il++];
}
while (ir < right.length) {
array[ia++] = right[ir++];
}
return array;
}
But I'm not sure how I can define default function fn to work the same as in JavaScript.
console.log([1, 2, 3, 10, 11, 100, 20].sort());
What should be the default sorting function to match those in the JavaScript engine? Should I convert numbers to strings and compare those? What is the proper implementation?
The default sort method as defined in core.js looks like so
var getSortCompare = function (comparefn) {
return function (x, y) {
if (y === undefined) return -1;
if (x === undefined) return 1;
if (comparefn !== undefined) return +comparefn(x, y) || 0;
return toString(x) > toString(y) ? 1 : -1;
};
Taken from this repo: https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/es.array.sort.js
Based on @jonrsharpe comments I was able to implement proper default function:
function defaultSortFn(a, b) {
if (typeof a !== 'string') {
a = String(a);
}
if (typeof b !== 'string') {
b = String(b);
}
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
}
that can be used in my sort:
Array.prototype.sort = function(fn = defaultSortFn) {
return mergeSort(fn, this);
};
The ECMAScript specification for Arra.prototype.sort mentions that the comparison (in absence of a comparator) involves:
e. Let xString be ? ToString(x).
f. Let yString be ? ToString(y).
g. Let xSmaller be ! IsLessThan(xString, yString, true).
h. If xSmaller is true, return -1𝔽.
i. Let ySmaller be ! IsLessThan(yString, xString, true).
j. If ySmaller is true, return 1𝔽.
k. Return +0𝔽.
Given that the IsLessThan procedure is also executed when two strings are compared with the < operator, we can faithfully replicate the default callback function as follows:
function (x, y) {
let xString = String(x);
let yString = String(y);
return xString < yString ? -1 : yString < xString ? 1 : 0;
}