open-data
Version:
A package filled with data structures, sort algorithms, selections, and more to come
258 lines (239 loc) • 7.21 kB
JavaScript
const getNativeComparator = (dataStruct) => {
if (dataStruct.every(elem => typeof elem === 'number')) {
return (a,b) => a < b;
} else if (dataStruct.every(elem => typeof elem === 'string')) {
return (a,b) => a < b;
} else if (dataStruct.every(elem => typeof elem === 'boolean')) {
return (a,b) => a ? false : (b ? true : false);
} else {
throw Error('Must provide a comparator for non-primitives');
}
}
const mergeSorted = (a,b, comparator=(a,b)=>a<b) => {
let result = [];
let currentA = 0;
let currentB = 0;
while (currentA !== a.length && currentB !== b.length) {
let nextA = a[currentA];
let nextB = b[currentB];
if (comparator(nextA, nextB)) {
result.push(nextA);
currentA ++;
} else {
result.push(nextB);
currentB ++;
}
}
if (currentA < a.length) {
result = result.concat(a.slice(currentA));
} else {
result = result.concat(b.slice(currentB));
}
return result;
}
const flatten = (arr) => {
return arr.reduce((flat, next) => flat.concat(next),[])
}
let last = (dataStruct) => {
return [...dataStruct][dataStruct.length-1];
}
const mergeSort = (dataStruct, comparator=getNativeComparator(dataStruct)) => {
let clone = [...dataStruct];
clone = clone.map(e => [e]);
let next = [];
let prev = clone;
while(prev.length > 1) {
if (prev.length % 2 === 1) {
let lastElement = mergeSorted(prev[prev.length-1], prev[prev.length-2], comparator);
prev.pop();
prev[prev.length-1] = lastElement;
}
for (let i = 0; i < prev.length; i += 2) {
if (prev[i] !== undefined && prev[i+1] !== undefined) {
next.push(mergeSorted(prev[i], prev[i+1], comparator));
}
}
prev = next;
next = [];
}
return prev[0] || [];
}
const isSorted = (dataStruct, comparator=(a,b)=>a<=b) => {
return [...dataStruct].every((e, i, arr) => i === arr.length -1 ? true : comparator(e, arr[i+1]))
}
const randomArray = (len, range) => {
let result = [];
for (let i = 0; i < len; i ++) {
result.push(Math.floor(Math.random()*range));
}
return result;
}
const swap = (dataStruct, i1, i2) => {
let temp = dataStruct[i1];
dataStruct[i1] = dataStruct[i2];
dataStruct[i2] = temp;
}
const quickSort = (dataStruct, comparator=getNativeComparator(dataStruct)) => {
let clone = [...dataStruct];
if (clone.length === 1 || clone.length === 0) {
return clone;
} else {
let pivotPoint = Math.floor(Math.random() * clone.length);
let above = clone.filter((e, i) => i !== pivotPoint && comparator(clone[pivotPoint], e));
let below = clone.filter((e, i) => i !== pivotPoint && !comparator(clone[pivotPoint], e));
return quickSort(below, comparator).concat(clone[pivotPoint]).concat(quickSort(above, comparator));
}
}
const insertionSort = (dataStruct, comparator = getNativeComparator(dataStruct)) => {
let result = [];
dataStruct.forEach(elem => {
let added = false;
for (let i = 0; i < result.length; i ++) {
if (comparator(elem, result[i]) && !added) {
result.splice(i, 0, elem);
added = true;
break;
}
}
if (!added) {
result.push(elem);
}
});
return result;
}
const bubbleSort = (dataStruct, comparator = getNativeComparator(dataStruct)) => {
let clone = [...dataStruct];
let swappedElems = true;
let times = 0;
while(swappedElems) {
swappedElems = false;
for (let i = 0; i < clone.length-times; i ++) {
if (i in clone && i + 1 in clone && comparator(clone[i+1], clone[i])) {
swap(clone, i, i+1);
swappedElems = true;
}
}
times ++;
}
return clone;
}
const selection = (dataStruct, comparator) => {
let select;
let first = true;
[...dataStruct].forEach(e => {
if (first && e !== undefined) {
select = e;
first = false;
} else if(e && comparator(e, select)) {
select = e;
}
});
return select;
}
const selectionSort = (dataStruct, comparator = getNativeComparator(dataStruct)) => {
let clone = [...dataStruct];
let result = [];
for (let i = 0; i < clone.length; i ++) {
let smallest = selection(clone, comparator);
result.push(smallest);
delete clone[clone.indexOf(smallest)];
}
return result;
};
const combSort = (dataStruct, comparator=getNativeComparator(dataStruct), combConst=1.3) => {
let clone = [...dataStruct];
let combLen = Math.floor(clone.length/combConst);
while(combLen > 1) {
for (let i = 0; i < clone.length-combLen; i++) {
if (i in clone && i + combConst in clone && comparator(clone[i], clone[i+combConst])) {
swap(clone, i, i+combConst);
}
}
combLen = Math.floor(combLen/combConst);
}
//Now it becomes bubbleSort because the elements that take a long time have been sorted.
return bubbleSort(clone, comparator);
}
const range = (dataStruct) => {
return [...dataStruct].reduce((m, next) => {
return {min: Math.min(m.min, next), max: Math.max(m.max, next)}
}, {min: Infinity, max: -Infinity});
}
const gnomeSort = (dataStruct) => {
let clone = [...dataStruct];
while(!isSorted(clone)) {
clone = clone.sort(()=>Math.random()-.5);
}
return clone;
}
const bucketSort = (dataStruct, comparator=getNativeComparator(dataStruct), bucketSizeFactor=2, otherSort=mergeSort) => {
if (typeof dataStruct[0] !== 'number') {
// Less efficient version for non numbers
let clone = [...dataStruct];
let buckets = [];
for (let i = 0; i < ~~Math.sqrt(clone.length); i++) {
buckets.push([]);
}
let i = 0;
clone.forEach(item => {
buckets[i].push(item);
i = (i + 1) % buckets.length;
});
buckets = buckets.map(bucket => {
return otherSort(bucket, comparator);
});
return combSort(flatten(buckets), comparator);
}
let dr = range(dataStruct);
dr.dist = dr.max - dr.min;
let clone = [...dataStruct];
if (dr.dist === 0) {
return clone;
}
let buckets = [];
for (let i = 0; i <= Math.ceil(dataStruct.length/Math.pow(dr.dist, 1/bucketSizeFactor)); i++) {
buckets.push([]);
}
clone.forEach(e => {
let index = ~~((buckets.length-1) * (e - dr.min)/dr.dist);
buckets[index].push(e);
});
return buckets.map(bucket => otherSort(bucket, comparator)).reduce((alr, next) => {
return alr.concat(next);
}, []);
}
const radixSort = (dataStruct, comparator=(a,b)=>a<b) => {
let clone = [...dataStruct];
let nextSort = [];
const convertToIndex = (thing) => {
if(typeof thing === 'number') {
return thing;
} else if (typeof thing === 'string') {
return thing.charCodeAt(0);
}
}
let maxLen = clone.reduce((maxLength, next) => Math.max(maxLength, next.toString().length), -Infinity);
for (let i = 0; i < maxLen; i++) {
clone.forEach(e => {
let index = [convertToIndex(e.toString()[e.toString().length-1-i]) || 0];
nextSort[index] = nextSort[index] || [];
nextSort[index].push(e);
});
clone = flatten(nextSort);
nextSort = [];
}
return clone;
}
const sort = {
insertion: insertionSort,
bubble: bubbleSort,
selection: selectionSort,
merge: mergeSort,
bucket: bucketSort,
radix: radixSort,
gnome: gnomeSort,
comb: combSort,
quick: quickSort,
isSorted,
}
module.exports = sort;