From 7bbd10f911e5cbe94b26a10dea92ae9eed4c8ce0 Mon Sep 17 00:00:00 2001 From: Eyal Arubas Date: Tue, 28 Oct 2014 10:30:43 +0800 Subject: [PATCH] 0.0.3 --- Makefile | 11 +- README.md | 2 +- bower.json | 6 +- dist/amd/sorter.js | 5 - dist/amd/unique.js | 33 ---- dist/cjs/sorter.js | 5 - dist/cjs/unique.js | 33 ---- dist/sorter.js | 13 ++ dist/unique.js | 83 +++++++++ package.json | 60 +++---- src/unique.js | 2 +- test/index.js | 435 ++++++++++++++++++++++++++++++++++++--------- unique.js | 15 -- 13 files changed, 490 insertions(+), 213 deletions(-) delete mode 100644 dist/amd/sorter.js delete mode 100644 dist/amd/unique.js delete mode 100644 dist/cjs/sorter.js delete mode 100644 dist/cjs/unique.js create mode 100644 dist/sorter.js create mode 100644 dist/unique.js delete mode 100644 unique.js diff --git a/Makefile b/Makefile index 6394210..7064687 100644 --- a/Makefile +++ b/Makefile @@ -17,16 +17,19 @@ dist_cjs: dist_amd: cd src && $(FUME) $(SRC_FILES) -amdify -o ../$(DIST_DIR)/amd && cd .. +dist_umd: + cd src && $(FUME) $(SRC_FILES) -umdify -o ../$(DIST_DIR) && cd .. + rm_dist: rm -rf $(DIST_DIR) -build: rm_dist dist_amd dist_cjs +build: rm_dist dist_umd test: build - $(MOCHA) --recursive --reporter spec $(TESTS_DIR) + $(MOCHA) --recursive --reporter spec $(TEST_DIR) coverage: build - $(ISTANBUL) cover $(_MOCHA) -- --recursive --reporter spec $(TESTS_DIR) + $(ISTANBUL) cover $(_MOCHA) -- --recursive --reporter spec $(TEST_DIR) travis: install build - $(ISTANBUL) cover --report lcovonly $(_MOCHA) -- --recursive --reporter spec --bail $(TESTS_DIR) && cat ./coverage/lcov.info | $(COVERALLS) + $(ISTANBUL) cover --report lcovonly $(_MOCHA) -- --recursive --reporter spec --bail $(TEST_DIR) && cat ./coverage/lcov.info | $(COVERALLS) diff --git a/README.md b/README.md index 65f276a..60043ef 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -[![Version](http://img.shields.io/npm/v/mu-unique.svg)](https://www.npmjs.org/package/mu-unique) [![Version](http://img.shields.io/bower/v/mu-unique.svg)](https://github.com/mu-lib/mu-unique) [![Build Status](https://api.travis-ci.org/mu-lib/mu-unique.svg?branch=master)](https://travis-ci.org/mu-lib/mu-unique) [![Coverage Status](https://img.shields.io/coveralls/mu-lib/mu-unique/master.svg)](https://coveralls.io/r/mu-lib/mu-unique) # mu-unique Uniqueify an array of elements with a natural or artificial order. **Runtime complexity:** `O(n*log(n))` `unique(arr, order)` 0. `arr {Array}` - The source array. 0. `order {Function}` - A custom order function. Optional. If a function is specified, it is called with 2 elements from the array and should return `0` if the are equal, a positive number if `a` is bigger and a negative number if `b` is bigger. **Notes:** 0. The function modifies the array and returns its new length. 0. The original order of items is not preserved. 0. If the `this` value of the function is defined, it will be used as the array (see examples). Thus it is possible to use this function to extend the Array prototype: `Array.prototype.unique = unique`. ## Installation - Node: 0. `npm install mu-unique` 0. `var unique = require('mu-unique');` - AMD (install with bower): 0. `bower install mu-unique` 0. `require(['mu-unique'], function(unique){ /* ... */ });` Build AMD and CJS dists with `make build`. Run tests with `make test`. Run coverage analysis with `make coverage` (coverage report is saved to `./coverage`). ## Examples ```Javascript var arr = [1, 2, 1, 2, 3], len = unique(arr); console.log(arr); // [1, 2, 3] console.log(len)l // 3 ``` **With a custom comparator:** ```Javascript var arr1 = ['hello', 'hi', 'world'], arr2 = unique(arr1, true, function(a, b){ // compare only first character return a[0] > b[0] ? 1 : a[0] < b[0] ? -1 : 0; }); console.log(arr1); // ['hello', 'hi', 'world'] console.log(arr2); // ['hello', 'world'] ``` **By setting the `this` value:** ```Javascript var arr = [1, 2, 1, 2, 3], len = unique.call(arr); console.log(arr); // [1, 2, 3] console.log(len)l // 3 ``` \ No newline at end of file +[![Version](http://img.shields.io/npm/v/mu-unique.svg)](https://www.npmjs.org/package/mu-unique) [![Version](http://img.shields.io/bower/v/mu-unique.svg)](https://github.com/mu-lib/mu-unique) [![Build Status](https://api.travis-ci.org/mu-lib/mu-unique.svg?branch=master)](https://travis-ci.org/mu-lib/mu-unique) [![Coverage Status](https://img.shields.io/coveralls/mu-lib/mu-unique/master.svg)](https://coveralls.io/r/mu-lib/mu-unique) # mu-unique Uniqueify an array of elements. **Runtime complexity:** `O(n*log(n))` for sortable arrays, `O(n^2)` for non-sortable arrays. `unique(arr, sortable, comparator)` 0. `arr {Array}` - The source array. 0. `sortable {Boolean}` - Optional. Does the array contain sortable elements? **defaults to `false`**. 0. `comparator {Function}` - Optional. - If the array is sortable, it defines the order of the elements in the array. It is called with 2 elements from the array and should return `0` if they are equal, a positive number if `a` is bigger and a negative number if `b` is bigger. If not provided, the array will be sorted with a natural order (as defined by the runtime). - If the array is not sortable, it defines the equality between elements in the array. It is called with 2 elements from the array and should return `true` if they are equal, and `false` otherwise. If not provided, the elements will be tested for equality with `===`. **Notes:** 0. The function modifies the array and returns its new length. 0. The original order of items may not be preserved. 0. If the `this` value of the function is defined, it will be used as the array (see examples). Thus it is possible to use this function to extend the Array prototype: `Array.prototype.unique = unique`. ## Installation - Node: 0. `npm install mu-unique` 0. `var unique = require('mu-unique');` - AMD (install with bower): 0. `bower install mu-unique` 0. `require(['mu-unique'], function(unique){ /* ... */ });` Build AMD and CJS dists with `make build`. Run tests with `make test`. Run coverage analysis with `make coverage` (coverage report is saved to `./coverage`). ## Examples ```Javascript var arr = [1, 2, 1, 2, 3], len = unique(arr); console.log(arr, true); // [1, 2, 3] console.log(len); // 3 ``` ```Javascript var o1 = {}, o2 = function(){}, o3 = "foo", arr = [o1,o1,o2,o3,o2,o3], len = unique(arr); console.log(arr); // [o1, o2, o3] console.log(len); // 3 ``` **With a custom order:** ```Javascript var arr1 = ['hello', 'hi', 'world'], arr2 = unique(arr1, function(a, b){ // compare only first character return a[0] > b[0] ? 1 : a[0] < b[0] ? -1 : 0; }); console.log(arr1); // ['hello', 'hi', 'world'] console.log(arr2); // ['hello', 'world'] ``` **By setting the `this` value:** ```Javascript var arr = [1, 2, 1, 2, 3], len = unique.call(arr); console.log(arr); // [1, 2, 3] console.log(len); // 3 ``` \ No newline at end of file diff --git a/bower.json b/bower.json index 1cb0ce5..909c76c 100644 --- a/bower.json +++ b/bower.json @@ -1,12 +1,12 @@ { "name": "mu-unique", - "version": "0.0.2", + "version": "0.0.3", "homepage": "https://github.com/mu-lib/mu-unique", "authors": [ "µLib Team (https://github.com/mu-lib)" ], "description": "Uniqueify an array", - "main": "./unique.js", + "main": "./dist/unique.js", "moduleType": [ "amd", "node" @@ -20,6 +20,8 @@ "license": "MIT", "ignore": [ "**/.*", + "makefile", + "src", "node_modules", "bower_components", "test", diff --git a/dist/amd/sorter.js b/dist/amd/sorter.js deleted file mode 100644 index cddd8c6..0000000 --- a/dist/amd/sorter.js +++ /dev/null @@ -1,5 +0,0 @@ -define([], function factory() { - return function (arr, order) { - Array.prototype.sort.call(arr, order); - }; -}); \ No newline at end of file diff --git a/dist/amd/unique.js b/dist/amd/unique.js deleted file mode 100644 index 84ed314..0000000 --- a/dist/amd/unique.js +++ /dev/null @@ -1,33 +0,0 @@ -define(['./sorter'], function factory(sorter) { - function trivialOrder(a, b) { - return a > b ? 1 : a < b ? -1 : 0; - } - function _uniqueifySorted(arr, order) { - var i = 0, n = 1, len = arr.length; - if (len < 2) - return; - while (i < len) { - if (order(arr[i], arr[n - 1]) !== 0) { - arr[n] = arr[i]; - n++; - } - i++; - } - arr.length = n; - } - return function (arr, order) { - order = order || trivialOrder; - if (typeof arr === 'function') { - order = arr; - arr = null; - } - arr = arr || this; - if (typeof order !== 'function') - throw Error('\'order\' must be a function'); - if (Object.prototype.toString.call(arr) !== '[object Array]') - throw Error('\'arr\' must be an array'); - sorter(arr, order); - _uniqueifySorted(arr, order); - return arr.length; - }; -}); \ No newline at end of file diff --git a/dist/cjs/sorter.js b/dist/cjs/sorter.js deleted file mode 100644 index 96be7f8..0000000 --- a/dist/cjs/sorter.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = function factory() { - return function (arr, order) { - Array.prototype.sort.call(arr, order); - }; -}(); \ No newline at end of file diff --git a/dist/cjs/unique.js b/dist/cjs/unique.js deleted file mode 100644 index 82f440e..0000000 --- a/dist/cjs/unique.js +++ /dev/null @@ -1,33 +0,0 @@ -module.exports = function factory(sorter) { - function trivialOrder(a, b) { - return a > b ? 1 : a < b ? -1 : 0; - } - function _uniqueifySorted(arr, order) { - var i = 0, n = 1, len = arr.length; - if (len < 2) - return; - while (i < len) { - if (order(arr[i], arr[n - 1]) !== 0) { - arr[n] = arr[i]; - n++; - } - i++; - } - arr.length = n; - } - return function (arr, order) { - order = order || trivialOrder; - if (typeof arr === 'function') { - order = arr; - arr = null; - } - arr = arr || this; - if (typeof order !== 'function') - throw Error('\'order\' must be a function'); - if (Object.prototype.toString.call(arr) !== '[object Array]') - throw Error('\'arr\' must be an array'); - sorter(arr, order); - _uniqueifySorted(arr, order); - return arr.length; - }; -}(require('./sorter')); \ No newline at end of file diff --git a/dist/sorter.js b/dist/sorter.js new file mode 100644 index 0000000..fcc3f2d --- /dev/null +++ b/dist/sorter.js @@ -0,0 +1,13 @@ +(function () { + if (typeof define === 'function' && define.amd) { + define([], factory); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else + throw Error('Cannot find a module loader'); + function factory() { + return function (arr, order) { + Array.prototype.sort.call(arr, order); + }; + } +}()); \ No newline at end of file diff --git a/dist/unique.js b/dist/unique.js new file mode 100644 index 0000000..b30e0b0 --- /dev/null +++ b/dist/unique.js @@ -0,0 +1,83 @@ +(function () { + if (typeof define === 'function' && define.amd) { + define(['./sorter'], uniqueFactory); + } else if (typeof exports === 'object') { + module.exports = uniqueFactory(require('./sorter')); + } else + throw Error('Cannot find a module loader'); + function uniqueFactory(sorter) { + var undefined, DEFAULT_SORTABLE = false; + function trivialOrder(a, b) { + return a > b ? 1 : a < b ? -1 : 0; + } + function trivialCompare(a, b) { + return a === b; + } + function _uniqueifySorted(arr, order) { + var i = 0, n = 1, len = arr.length; + if (len < 2) + return; + while (i < len) { + if (order(arr[i], arr[n - 1]) !== 0) { + arr[n] = arr[i]; + n++; + } + i++; + } + arr.length = n; + } + function _uniqueifyNotSorted(arr, compare) { + var i = 0, j, len = arr.length; + while (i < len) { + j = i + 1; + while (j < len) { + if (compare(arr[i], arr[j])) { + arr[j--] = arr[--len]; + } + j++; + } + i++; + } + arr.length = len; + } + return function () { + var arr, sortable, comparator, args = Array.prototype.slice.call(arguments, 0); + if (args.length === 0) + args.push(this); + if (args.length === 1) { + if (Object.prototype.toString.call(args[0]) !== '[object Array]') + args.unshift(this); + else + args.push(DEFAULT_SORTABLE); + } + if (args.length === 2) { + if (Object.prototype.toString.call(args[0]) !== '[object Array]') { + args.unshift(this); + } else if (args[1] === true) { + args.push(trivialOrder); + } else if (args[1] === false) { + args.push(trivialCompare); + } else { + args[2] = args[1]; + args[1] = DEFAULT_SORTABLE; + } + } + arr = args[0]; + sortable = args[1]; + comparator = args[2]; + if (Object.prototype.toString.call(arr) !== '[object Array]') + throw Error('\'arr\' must be an array'); + if (!(sortable === true || sortable === false)) + throw Error('\'sortable\' must be a boolean'); + if (!(typeof comparator === 'function')) + throw Error('\'comparator\' must be a function'); + if (sortable) { + sorter(arr, comparator); + _uniqueifySorted(arr, comparator); + } else { + _uniqueifyNotSorted(arr, comparator); + } + return arr.length; + }; + } +}()); \ No newline at end of file diff --git a/package.json b/package.json index b861b47..eb26f1c 100644 --- a/package.json +++ b/package.json @@ -1,32 +1,32 @@ { - "name": "mu-unique", - "version": "0.0.2", - "description": "Uniqueify an array", - "main": "unique.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "https://github.com/mu-lib/mu-unique.git" - }, - "keywords": [ - "unique", - "array", - "in-place", - "comparator" - ], - "author": "µLib Team (https://github.com/mu-lib)", - "license": "MIT", - "bugs": { - "url": "https://github.com/mu-lib/mu-unique/issues" - }, - "homepage": "https://github.com/mu-lib/mu-unique", - "devDependencies": { - "coveralls": "^2.11.2", - "fume": "0.0.0", - "istanbul": "^0.3.2", - "mocha": "^1.21.5", - "should": "^4.1.0" - } + "name": "mu-unique", + "version": "0.0.3", + "description": "Uniqueify an array", + "main": "dist/unique.js", + "scripts": { + "test": "make test" + }, + "repository": { + "type": "git", + "url": "https://github.com/mu-lib/mu-unique.git" + }, + "keywords": [ + "unique", + "array", + "in-place", + "comparator" + ], + "author": "µLib Team (https://github.com/mu-lib)", + "license": "MIT", + "bugs": { + "url": "https://github.com/mu-lib/mu-unique/issues" + }, + "homepage": "https://github.com/mu-lib/mu-unique", + "devDependencies": { + "coveralls": "^2.11.2", + "fume": "0.0.1", + "istanbul": "^0.3.2", + "mocha": "^1.21.5", + "should": "^4.1.0" + } } diff --git a/src/unique.js b/src/unique.js index e9e0139..ecb777c 100644 --- a/src/unique.js +++ b/src/unique.js @@ -1 +1 @@ -/** * @name unique */ function factory(sorter) { /** * Order defined by the language runtime. * @param a * @param b * @returns {number} */ function trivialOrder(a, b) { return a > b ? 1 : a < b ? -1 : 0; } /** * Assume a sorted array. Remove duplicate elements with one pass. * @param arr A sorted array * @param order * @returns The new length of the array. */ function _uniqueifySorted(arr, order) { var i = 0, n = 1, len = arr.length; if (len < 2) return; while (i < len) { if (order(arr[i], arr[n - 1]) !== 0) { arr[n] = arr[i]; n++; } i++; } arr.length = n; } return function (arr, order) { order = order || trivialOrder; if (typeof arr === 'function') { order = arr; arr = null; } arr = arr || this; if (typeof order !== 'function') throw Error("'order' must be a function"); if (Object.prototype.toString.call(arr) !== '[object Array]') throw Error("'arr' must be an array"); sorter(arr, order); _uniqueifySorted(arr, order); return arr.length; }; } \ No newline at end of file +/** * @name unique */ function uniqueFactory(sorter) { var undefined, DEFAULT_SORTABLE = false; function trivialOrder(a, b) { return a > b ? 1 : a < b ? -1 : 0; } function trivialCompare(a, b) { return a === b; } /** * Assume a sorted array. Remove duplicate elements with one pass. * @param arr A sorted array * @param order * @private */ function _uniqueifySorted(arr, order) { var i = 0, n = 1, len = arr.length; if (len < 2) return; while (i < len) { if (order(arr[i], arr[n - 1]) !== 0) { arr[n] = arr[i]; n++; } i++; } arr.length = n; } /** * Assume an unsorted array. Removes duplicates with two nested loops. * @param arr * @param compare * @private */ function _uniqueifyNotSorted(arr, compare) { var i = 0, j, len = arr.length; while (i < len) { j = i + 1; while (j < len) { if (compare(arr[i], arr[j])) { arr[j--] = arr[--len]; } j++; } i++; } arr.length = len; } /** * Uniqueify an array. * @param arr the array to uniqueify * @param sortable is this array sortable? * @param comparator a function which defines an order for the elements in * the array (if the array is sortabel), or elements equality if it is not. */ return function () { var arr, sortable, comparator, args = Array.prototype.slice.call(arguments, 0); if (args.length === 0) args.push(this); if (args.length === 1) { if (Object.prototype.toString.call(args[0]) !== '[object Array]') args.unshift(this); else args.push(DEFAULT_SORTABLE); } if (args.length === 2) { if (Object.prototype.toString.call(args[0]) !== '[object Array]') { args.unshift(this); } else if (args[1] === true) { args.push(trivialOrder); } else if (args[1] === false) { args.push(trivialCompare); } else { args[2] = args[1]; args[1] = DEFAULT_SORTABLE; } } arr = args[0]; sortable = args[1]; comparator = args[2]; if (Object.prototype.toString.call(arr) !== '[object Array]') throw Error("'arr' must be an array"); if (!(sortable === true || sortable === false)) throw Error("'sortable' must be a boolean"); if (!(typeof comparator === 'function')) throw Error("'comparator' must be a function"); if (sortable) { sorter(arr, comparator); _uniqueifySorted(arr, comparator); } else { _uniqueifyNotSorted(arr, comparator); } return arr.length; }; } \ No newline at end of file diff --git a/test/index.js b/test/index.js index c4480e4..5ad262c 100644 --- a/test/index.js +++ b/test/index.js @@ -27,16 +27,33 @@ describe("arguments validation", function () { }); - describe("run with invalid ordering", function () { + describe("run with invalid sortable", function () { it("should throw an error", function () { uniqueify.bind(null, [1, 2, 3], 123).should.throwError(); uniqueify.bind(null, [1, 2, 3], "foo").should.throwError(); - uniqueify.bind(null, [1, 2, 3], {a: 'b'}).should.throwError(); + uniqueify.bind(null, [1, 2, 3], {a: 'b'}, function () { + }).should.throwError(); uniqueify.bind([1, 2, 3], 123).should.throwError(); uniqueify.bind([1, 2, 3], "foo").should.throwError(); - uniqueify.bind([1, 2, 3], {a: 'b'}).should.throwError(); + uniqueify.bind([1, 2, 3], {a: 'b'}, function () { + }).should.throwError(); + + }); + + }); + + describe("run with invalid comparator", function () { + + it("should throw an error", function () { + + uniqueify.bind(null, [1, 2, 3], true, 123).should.throwError(); + uniqueify.bind(null, [1, 2, 3], true, "foo").should.throwError(); + uniqueify.bind(null, [1, 2, 3], false, {a: 'b'}).should.throwError(); + uniqueify.bind([1, 2, 3], false, 123).should.throwError(); + uniqueify.bind([1, 2, 3], true, "foo").should.throwError(); + uniqueify.bind([1, 2, 3], true, {a: 'b'}).should.throwError(); }); @@ -56,31 +73,81 @@ describe("arguments validation", function () { describe("without setting 'this'", function () { - describe("without a custom order", function () { + describe("with sortable array", function () { + + describe("without a custom sorter", function () { + + describe("unique numbers", function () { + + var arr = [4, 3, 1, 1, 1, 4, 3, 2, 2, 2, 0], + unique = [0, 1, 2, 3, 4]; + + it('should uniqueify the array', function () { + + should.equal(unique.length, uniqueify(arr, true)); + arr.should.containDeep(unique); + + }); - describe("unique numbers", function () { + }); + + describe("unique strings", function () { - var arr = [4, 3, 1, 1, 1, 4, 3, 2, 2, 2, 0], - unique = [0, 1, 2, 3, 4]; + var arr = ["world", "hi", "hello", "hi", "hello"], + unique = ["hello", "hi", "world"]; - it('should uniqueify the array', function () { + it('should uniqueify the array', function () { - should.equal(unique.length, uniqueify(arr)); - should.deepEqual(arr, unique); + should.equal(unique.length, uniqueify(arr, true)); + arr.should.containDeep(unique); + + }); }); }); - describe("unique strings", function () { + describe("with a custom sorter", function () { + + describe("unique strings by first letter", function () { + + var arr = ["world", "hi", "hello", "hi", "hello"], + unique = ["hi", "world"]; + + it('should uniqueify the array', function () { + + should.equal(unique.length, uniqueify(arr, true, function (a, b) { + return a[0] > b[0] ? 1 : a[0] > b[0] ? -1 : 0; + })); + arr.should.containDeep(unique); - var arr = ["world", "hi", "hello", "hi", "hello"], - unique = ["hello", "hi", "world"]; + }); - it('should uniqueify the array', function () { + }); + + describe("unique objects by field", function () { + + var arr = [ + {id: 1}, + {id: 1}, + {id: 2}, + {id: 1}, + {id: 3} + ], + unique = [ + {id: 1}, + {id: 2}, + {id: 3} + ]; + + it('should uniqueify the array', function () { - should.equal(unique.length, uniqueify(arr)); - should.deepEqual(arr, unique); + should.equal(unique.length, uniqueify(arr, true, function (a, b) { + return a.id > b.id ? 1 : a.id < b.id ? -1 : 0; + })); + arr.should.containDeep(unique); + + }); }); @@ -88,45 +155,120 @@ describe("without setting 'this'", function () { }); - describe("with a custom order", function () { + describe("with unsortable array", function () { + + describe("without a custom comparator", function () { + + describe("unique numbers", function () { - describe("unique strings by first letter", function () { + var arr = [4, 3, 1, 1, 1, 4, 3, 2, 2, 2, 0], + unique = [0, 1, 2, 3, 4]; - var arr = ["world", "hi", "hello", "hi", "hello"], - unique = ["hi", "world"]; + it('should uniqueify the array', function () { - it('should uniqueify the array', function () { + should.equal(unique.length, uniqueify(arr, false)); + arr.should.containDeep(unique); - should.equal(unique.length, uniqueify(arr, function (a, b) { - return a[0] > b[0] ? 1 : a[0] < b[0] ? -1 : 0; - })); - should.deepEqual(arr, unique); + }); + + }); + + describe("unique strings", function () { + + var arr = ["world", "hi", "hello", "hi", "hello"], + unique = ["hello", "hi", "world"]; + + it('should uniqueify the array', function () { + + should.equal(unique.length, uniqueify(arr, false)); + arr.should.containDeep(unique); + + }); + + }); + + describe("unique objects", function () { + + var o1 = {a: 'a'}, o2 = {b: 'b'}, o3 = {c: 'c'}, + arr = [o1, o1, o2, o3, o2, o1, o3, o2], + unique = [o1, o2, o3]; + + it('should uniqueify the array', function () { + + should.equal(unique.length, uniqueify(arr, false)); + arr.should.containDeep(unique); + + }); + + }); + + describe("unique functions", function () { + + var f1 = function () { + }, + f2 = function () { + return true; + }, + f3 = function () { + return false; + }, + f4 = function () { + }, + arr = [f1, f2, f2, f1, f4, f1, f2, f4, f3, f3, f4], + unique = [f1, f2, f3, f4]; + + it('should uniqueify the array', function () { + + should.equal(unique.length, uniqueify(arr, false)); + arr.should.containDeep(unique); + + }); }); }); - describe("unique objects by field", function () { + describe("with a custom comparator", function () { - var arr = [ - {id: 1}, - {id: 1}, - {id: 2}, - {id: 1}, - {id: 3} - ], - unique = [ - {id: 1}, - {id: 2}, - {id: 3} - ]; + describe("unique strings by first letter", function () { - it('should uniqueify the array', function () { + var arr = ["world", "hi", "hello", "hi", "hello"], + unique = ["hi", "world"]; - should.equal(unique.length, uniqueify(arr, function (a, b) { - return a.id - b.id; - })); - should.deepEqual(arr, unique); + it('should uniqueify the array', function () { + + should.equal(unique.length, uniqueify(arr, false, function (a, b) { + return a[0] === b[0]; + })); + arr.should.containDeep(unique); + + }); + + }); + + describe("unique objects by field", function () { + + var arr = [ + {id: 1}, + {id: 1}, + {id: 2}, + {id: 1}, + {id: 3} + ], + unique = [ + {id: 1}, + {id: 2}, + {id: 3} + ]; + + it('should uniqueify the array', function () { + + should.equal(unique.length, uniqueify(arr, false, function (a, b) { + return a.id === b.id; + })); + arr.should.containDeep(unique); + + }); }); @@ -138,31 +280,81 @@ describe("without setting 'this'", function () { describe("with setting 'this'", function () { - describe("without a custom order", function () { + describe("with sortable array", function () { + + describe("without a custom sorter", function () { + + describe("unique numbers", function () { + + var arr = [4, 3, 1, 1, 1, 4, 3, 2, 2, 2, 0], + unique = [0, 1, 2, 3, 4]; + + it('should uniqueify the array', function () { - describe("unique numbers", function () { + should.equal(unique.length, uniqueify.call(arr, true)); + arr.should.containDeep(unique); - var arr = [4, 3, 1, 1, 1, 4, 3, 2, 2, 2, 0], - unique = [0, 1, 2, 3, 4]; + }); - it('should uniqueify the array', function () { + }); + + describe("unique strings", function () { + + var arr = ["world", "hi", "hello", "hi", "hello"], + unique = ["hello", "hi", "world"]; + + it('should uniqueify the array', function () { - should.equal(unique.length, uniqueify.call(arr)); - should.deepEqual(arr, unique); + should.equal(unique.length, uniqueify.call(arr, true)); + arr.should.containDeep(unique); + + }); }); }); - describe("unique strings", function () { + describe("with a custom sorter", function () { + + describe("unique strings by first letter", function () { + + var arr = ["world", "hi", "hello", "hi", "hello"], + unique = ["hi", "world"]; - var arr = ["world", "hi", "hello", "hi", "hello"], - unique = ["hello", "hi", "world"]; + it('should uniqueify the array', function () { - it('should uniqueify the array', function () { + should.equal(unique.length, uniqueify.call(arr, true, function (a, b) { + return a[0] > b[0] ? 1 : a[0] > b[0] ? -1 : 0; + })); + arr.should.containDeep(unique); - should.equal(unique.length, uniqueify.call(arr)); - should.deepEqual(arr, unique); + }); + + }); + + describe("unique objects by field", function () { + + var arr = [ + {id: 1}, + {id: 1}, + {id: 2}, + {id: 1}, + {id: 3} + ], + unique = [ + {id: 1}, + {id: 2}, + {id: 3} + ]; + + it('should uniqueify the array', function () { + + should.equal(unique.length, uniqueify.call(arr, true, function (a, b) { + return a.id > b.id ? 1 : a.id < b.id ? -1 : 0; + })); + arr.should.containDeep(unique); + + }); }); @@ -170,45 +362,120 @@ describe("with setting 'this'", function () { }); - describe("with a custom order", function () { + describe("with unsortable array", function () { + + describe("without a custom sorter", function () { + + describe("unique numbers", function () { + + var arr = [4, 3, 1, 1, 1, 4, 3, 2, 2, 2, 0], + unique = [0, 1, 2, 3, 4]; + + it('should uniqueify the array', function () { + + should.equal(unique.length, uniqueify.call(arr, false)); + arr.should.containDeep(unique); + + }); - describe("unique strings by first letter", function () { + }); + + describe("unique strings", function () { + + var arr = ["world", "hi", "hello", "hi", "hello"], + unique = ["hello", "hi", "world"]; + + it('should uniqueify the array', function () { + + should.equal(unique.length, uniqueify.call(arr, false)); + arr.should.containDeep(unique); + + }); + + }); + + describe("unique objects", function () { - var arr = ["world", "hi", "hello", "hi", "hello"], - unique = ["hi", "world"]; + var o1 = {a: 'a'}, o2 = {b: 'b'}, o3 = {c: 'c'}, + arr = [o1, o1, o2, o3, o2, o1, o3, o2], + unique = [o1, o2, o3]; - it('should uniqueify the array', function () { + it('should uniqueify the array', function () { - should.equal(unique.length, uniqueify.call(arr, function (a, b) { - return a[0] > b[0] ? 1 : a[0] < b[0] ? -1 : 0; - })); - should.deepEqual(arr, unique); + should.equal(unique.length, uniqueify.call(arr, false)); + arr.should.containDeep(unique); + + }); + + }); + + describe("unique functions", function () { + + var f1 = function () { + }, + f2 = function () { + return true; + }, + f3 = function () { + return false; + }, + f4 = function () { + }, + arr = [f1, f2, f2, f1, f4, f1, f2, f4, f3, f3, f4], + unique = [f1, f2, f3, f4]; + + it('should uniqueify the array', function () { + + should.equal(unique.length, uniqueify.call(arr, false)); + arr.should.containDeep(unique); + + }); }); }); - describe("unique objects by field", function () { + describe("with a custom sorter", function () { + + describe("unique strings by first letter", function () { - var arr = [ - {id: 1}, - {id: 1}, - {id: 2}, - {id: 1}, - {id: 3} - ], - unique = [ - {id: 1}, - {id: 2}, - {id: 3} - ]; + var arr = ["world", "hi", "hello", "hi", "hello"], + unique = ["hi", "world"]; - it('should uniqueify the array', function () { + it('should uniqueify the array', function () { - should.equal(unique.length, uniqueify.call(arr, function (a, b) { - return a.id - b.id; - })); - should.deepEqual(arr, unique); + should.equal(unique.length, uniqueify.call(arr, false, function (a, b) { + return a[0] === b[0]; + })); + arr.should.containDeep(unique); + + }); + + }); + + describe("unique objects by field", function () { + + var arr = [ + {id: 1}, + {id: 1}, + {id: 2}, + {id: 1}, + {id: 3} + ], + unique = [ + {id: 1}, + {id: 2}, + {id: 3} + ]; + + it('should uniqueify the array', function () { + + should.equal(unique.length, uniqueify.call(arr, false, function (a, b) { + return a.id === b.id; + })); + arr.should.containDeep(unique); + + }); }); @@ -216,4 +483,4 @@ describe("with setting 'this'", function () { }); -}); \ No newline at end of file +}); diff --git a/unique.js b/unique.js deleted file mode 100644 index 463f138..0000000 --- a/unique.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -/* istanbul ignore next */ - -if (typeof define === 'function' && define.amd) { - - define(['./dist/amd/unique'], function(unique) { - return unique; - }); - -} else if (typeof exports === 'object') { - - module.exports = require('./dist/cjs/unique'); - -} else throw Error("Cannot find a module loader");