diff --git a/snippets/stableSort.md b/snippets/stableSort.md new file mode 100644 index 000000000..929b34f09 --- /dev/null +++ b/snippets/stableSort.md @@ -0,0 +1,29 @@ +### stableSort + +Performs stable sort. Useful in Chrome and NodeJS. + +Use `Array.map()` to pair each element of the input array with its corresponding index. Then use `Array.sort()` and a user provided `compare()` function. If the items are equal, sort them by their initial index in the input array. Lastly use `Array.map()` to convert back to the initial array items. +Returns new array without modifying the initial one. + +```js +var stableSort = (arr, compare) => + arr + .map((item, index) => ({ item, index })) + .sort((a, b) => + ((result = compare(a.item, b.item)) => (result !== 0 ? result : a.index - b.index))() + ) + .map(({ item }) => item); +``` + +```js +var str = 'abcdefghijklmnopqrstuvwxyz'; +var compare = (a, b) => ~~(str.indexOf(b) / 2.3) - ~~(str.indexOf(a) / 2.3); + +// default Array.sort() is unstable in Chrome and NodeJS + modifies the input array +var arr1 = str.split(''); +console.log(arr1.sort(compare).join('') === 'xyzvwtursopqmnklhijfgdeabc'); // false + +// stable sort + returns new array +var arr2 = str.split(''); +console.log(stableSort(arr2, compare).join('') === 'xyzvwtursopqmnklhijfgdeabc'); // true +``` diff --git a/tag_database b/tag_database index 71ed6c7b6..3e5d0e839 100644 --- a/tag_database +++ b/tag_database @@ -221,6 +221,7 @@ sortedLastIndex:array,math sortedLastIndexBy:array,math,function splitLines:string spreadOver:adapter +stableSort:array,sort standardDeviation:math,array stripHTMLTags:string,utility,regexp sum:math,array diff --git a/test/stableSort/stableSort.js b/test/stableSort/stableSort.js new file mode 100644 index 000000000..d5b5db0c8 --- /dev/null +++ b/test/stableSort/stableSort.js @@ -0,0 +1,8 @@ +var stableSort = (arr, compare) => +arr +.map((item, index) => ({ item, index })) +.sort((a, b) => +((result = compare(a.item, b.item)) => (result !== 0 ? result : a.index - b.index))() +) +.map(({ item }) => item); +module.exports = stableSort; \ No newline at end of file diff --git a/test/stableSort/stableSort.test.js b/test/stableSort/stableSort.test.js new file mode 100644 index 000000000..50e1bbe6b --- /dev/null +++ b/test/stableSort/stableSort.test.js @@ -0,0 +1,25 @@ +const test = require('tape'); +const stableSort = require('./stableSort.js'); + +test('Testing stableSort', (t) => { + //For more information on all the methods supported by tape + //Please go to https://github.com/substack/tape + t.true(typeof stableSort === 'function', 'stableSort is a Function'); + //t.deepEqual(stableSort(args..), 'Expected'); + //t.equal(stableSort(args..), 'Expected'); + //t.false(stableSort(args..), 'Expected'); + //t.throws(stableSort(args..), 'Expected'); + + // test if js engine's Array#sort implementation is stable + // https://gist.github.com/leeoniya/5816476 + var str = 'abcdefghijklmnopqrstuvwxyz'; + var compare = (a, b) => ~~(str.indexOf(b) / 2.3) - ~~(str.indexOf(a) / 2.3); + + var input = str.split(''); + var output = stableSort(input, compare); + + t.equal(output.join(''), 'xyzvwtursopqmnklhijfgdeabc'); + t.notDeepEqual(input, output); + + t.end(); +}); \ No newline at end of file