turniere-frontend/js/utils/sort.js

74 lines
2.2 KiB
JavaScript

/**
* Constants for the ordering in which the sorting
* algorithm should bring the elements.
*/
export const Order = {
ascending : 1,
descending: 2
};
/**
* A sorting function that can be used to sort any kind of data
* given an applicable comparator. Said comparator will take in two
* elements of the given array `data`, and produce an integer result
* which can be interpreted as follows:
* ```
* comparator(a, b) < 0 => a < b
* comparator(a, b) = 0 => a = b
* comparator(a, b) > 0 => a > b
* ```
* The parameter order should be given as one of the constants in Order.
* Said `order` parameter is optional; it will default to ascending.
*
* @param {T[]} data The array that is to be sorted.
* @param {(T, T) => int} comparator A function which can be used
* to compare any two elemments from the given array.
* @param {int} order The order in which the data should be sorted,
* as defined in Order.
* @return An array with the elements from data sorted in the given order.
*/
export function sort(data, comparator, order) {
if(order === undefined) {
order = Order.ascending;
}
let target = data.slice();
return sortToTarget(data, target, 0, data.length, comparator, order);
}
function sortToTarget(data, target, start, end, comparator, order) {
if(end - start < 2) {
return data;
}
let middle = Math.floor((end + start) / 2);
sortToTarget(target, data, start, middle, comparator, order);
sortToTarget(target, data, middle, end, comparator, order);
return merge(data, target, start, middle, end, comparator, order);
}
function merge(data, target, start, middle, end, comparator, order) {
let i = start;
let j = middle;
for(let k = start; k < end; k++) {
if(order === Order.ascending) {
if(i < middle && (j >= end || comparator(data[i], data[j]) >= 0)) {
target[k] = data[i++];
} else {
target[k] = data[j++];
}
} else {
if(i < middle && (j >= end || comparator(data[i], data[j]) <= 0)) {
target[k] = data[i++];
} else {
target[k] = data[j++];
}
}
}
return target;
}