From 9552e42e2d34686067bf27285f35e19303d35231 Mon Sep 17 00:00:00 2001 From: Luke Murray Date: Mon, 27 Mar 2017 14:06:15 +0100 Subject: [PATCH 1/4] Added static sortBy function. --- src/seamless-immutable.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/seamless-immutable.js b/src/seamless-immutable.js index 9e458cc..fa41c41 100644 --- a/src/seamless-immutable.js +++ b/src/seamless-immutable.js @@ -577,6 +577,21 @@ function immutableInit(config) { return result; } + function sortBy(array, sorter) { + var result = [], i, length; + + if (!(array instanceof Array)) { + throw new TypeError("The first argument to Immutable#sortBy must be an array."); + } + + for (i = 0, length = array.length; i < length; i++) { + result.push(array[i]); + } + result.sort(sorter); + + return makeImmutableArray(result); + } + // Creates plain object to be used for cloning function instantiatePlainObject() { return {}; @@ -719,6 +734,7 @@ function immutableInit(config) { Immutable.getIn = toStatic(getIn); Immutable.flatMap = toStatic(flatMap); Immutable.asObject = toStatic(asObject); + Immutable.sortBy = sortBy; if (!globalConfig.use_static) { Immutable.static = immutableInit({ use_static: true From be58fd9e8d452f10008c5bb7f49d8f76ea11fd8c Mon Sep 17 00:00:00 2001 From: Luke Murray Date: Mon, 27 Mar 2017 14:09:49 +0100 Subject: [PATCH 2/4] Added tests for static immutable sortBy function. --- test/ImmutableArray.spec.js | 2 ++ test/ImmutableArray/test-sortBy.js | 46 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 test/ImmutableArray/test-sortBy.js diff --git a/test/ImmutableArray.spec.js b/test/ImmutableArray.spec.js index 8518aa0..744e745 100644 --- a/test/ImmutableArray.spec.js +++ b/test/ImmutableArray.spec.js @@ -5,6 +5,7 @@ var testAsMutable = require("./ImmutableArray/test-asMutable.js"); var testSet = require("./ImmutableArray/test-set.js"); var testUpdate = require("./ImmutableArray/test-update.js"); var testGetIn = require("./ImmutableArray/test-getIn.js"); +var testSortBy = require("./ImmutableArray/test-sortBy"); var devBuild = require("../seamless-immutable.development.js"); var prodBuild = require("../seamless-immutable.production.min.js"); var getTestUtils = require("./TestUtils.js"); @@ -25,6 +26,7 @@ var getTestUtils = require("./TestUtils.js"); testSet(config); testUpdate(config); testGetIn(config); + testSortBy(config); }); }); }); diff --git a/test/ImmutableArray/test-sortBy.js b/test/ImmutableArray/test-sortBy.js new file mode 100644 index 0000000..22e7beb --- /dev/null +++ b/test/ImmutableArray/test-sortBy.js @@ -0,0 +1,46 @@ +var JSC = require("jscheck"); +var getTestUtils = require("../TestUtils.js"); + +module.exports = function(config) { + var Immutable = config.implementation; + var TestUtils = getTestUtils(Immutable); + var check = TestUtils.check; + + function dummySorter(a, b) { + if(b > a) { + return 1; + } else if(b < a) { + return -1; + } else { + return 0; + } + } + + describe("#sortBy", function() { + it("produces a sorted immutable array", function() { + check(100, [ JSC.array(JSC.integer(4), JSC.any()) ], function(array) { + var immutable = Immutable(array); + var mutable = array.slice(); + + var resultImmutable = Immutable.sortBy(immutable); + var resultMutable = mutable.slice(); + resultMutable.sort(); + + TestUtils.assertJsonEqual(resultImmutable, resultMutable); + }); + }); + + it("produces a sorted immutable array when provided with a sorter function", function() { + check(100, [ JSC.array(JSC.integer(4), JSC.any()) ], function(array) { + var immutable = Immutable(array); + var mutable = array.slice(); + + var resultImmutable = Immutable.sortBy(immutable, dummySorter); + var resultMutable = mutable.slice(); + resultMutable.sort(dummySorter); + + TestUtils.assertJsonEqual(resultImmutable, resultMutable); + }); + }); + }); +}; From dfe18aab77012dbb2eee74f35f67578c17640ff3 Mon Sep 17 00:00:00 2001 From: Luke Murray Date: Mon, 27 Mar 2017 14:34:18 +0100 Subject: [PATCH 3/4] Added sortBy to README.md --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index a918343..c755978 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,26 @@ Immutable.from([1, 2, 3]); Immutable([1, 2, 3]) ``` +## Immutable.sortBy + +JavaScript's Array `sort()` is a mutating function and its use will throw an ImmutableError. This has been done rather than override the `sort()` method with one that returns an immutable Array. The rationale for this is that returning an immutable array from the `sort()` function would be a surprising change to the expected behavior for developers unfamiliar with immutables. However, a convenient method for creating a sorted immutable array from an unsorted one is still desirable. This function closes this gap. + +```javascript +var array = Immutable([1, 3, 2]); +var sortedArray = Immutable.sortBy(array); +// returns Immutable([1, 2, 3]); +``` + +This function also accepts an optional sorting function as per the original `sort()`: + +```javascript +var array = Immutable([1, 3, 2]); +var sortedArray = Immutable.sortBy(array, function(a, b) { + return b - a; +}); +// returns Immutable([3, 2, 1]); +``` + ## Immutable Array Like a regular Array, but immutable! You can construct these by passing From 7eecb314cd9f36db998af0c34e2040533e160bc8 Mon Sep 17 00:00:00 2001 From: Luke Murray Date: Fri, 28 Apr 2017 10:37:07 +0100 Subject: [PATCH 4/4] Attempts to sort an already sorted array now return the original array. --- src/seamless-immutable.js | 25 +++++++++- test/ImmutableArray/test-sortBy.js | 80 +++++++++++++++++------------- 2 files changed, 69 insertions(+), 36 deletions(-) diff --git a/src/seamless-immutable.js b/src/seamless-immutable.js index fa41c41..a656dfd 100644 --- a/src/seamless-immutable.js +++ b/src/seamless-immutable.js @@ -578,7 +578,7 @@ function immutableInit(config) { } function sortBy(array, sorter) { - var result = [], i, length; + var result = [], i, length, rearranged; if (!(array instanceof Array)) { throw new TypeError("The first argument to Immutable#sortBy must be an array."); @@ -589,7 +589,28 @@ function immutableInit(config) { } result.sort(sorter); - return makeImmutableArray(result); + // Test if elements of the array have been rearranged + rearranged = false; + for (i = 0, length = array.length; i < length; i++) { + if(result[i] !== array[i]) { + // Check if both are NaN. Type checks catch cases where isNaN returns true for strings. + if(!(typeof result[i] === "number" && isNaN(result[i]) && typeof array[i] === "number" && isNaN(array[i]))) { + rearranged = true; + } + } + } + + // If the elements haven't been rearranged, return the original immutable + if(rearranged) { + return makeImmutableArray(result); + } else { + // Ensure that the returned array is immutable + if(isImmutable(array)) { + return array; + } else { + return makeImmutableArray(array); + } + } } // Creates plain object to be used for cloning diff --git a/test/ImmutableArray/test-sortBy.js b/test/ImmutableArray/test-sortBy.js index 22e7beb..4af0954 100644 --- a/test/ImmutableArray/test-sortBy.js +++ b/test/ImmutableArray/test-sortBy.js @@ -1,46 +1,58 @@ -var JSC = require("jscheck"); +var JSC = require("jscheck"); var getTestUtils = require("../TestUtils.js"); +var assert = require("chai").assert; module.exports = function(config) { - var Immutable = config.implementation; - var TestUtils = getTestUtils(Immutable); - var check = TestUtils.check; - - function dummySorter(a, b) { - if(b > a) { - return 1; - } else if(b < a) { - return -1; - } else { - return 0; + var Immutable = config.implementation; + var TestUtils = getTestUtils(Immutable); + var check = TestUtils.check; + + function dummySorter(a, b) { + if(b > a) { + return 1; + } else if(b < a) { + return -1; + } else { + return 0; + } } - } - describe("#sortBy", function() { - it("produces a sorted immutable array", function() { - check(100, [ JSC.array(JSC.integer(4), JSC.any()) ], function(array) { - var immutable = Immutable(array); - var mutable = array.slice(); + describe("#sortBy", function() { + it("produces a sorted immutable array", function() { + check(100, [JSC.array(JSC.integer(4), JSC.any())], function(array) { + var immutable = Immutable(array); + var mutable = array.slice(); - var resultImmutable = Immutable.sortBy(immutable); - var resultMutable = mutable.slice(); - resultMutable.sort(); + var resultImmutable = Immutable.sortBy(immutable); + var resultMutable = mutable.slice(); + resultMutable.sort(); - TestUtils.assertJsonEqual(resultImmutable, resultMutable); - }); - }); + TestUtils.assertJsonEqual(resultImmutable, resultMutable); + }); + }); + + it("produces a sorted immutable array when provided with a sorter function", function() { + check(100, [JSC.array(JSC.integer(4), JSC.any())], function(array) { + var immutable = Immutable(array); + var mutable = array.slice(); + + var resultImmutable = Immutable.sortBy(immutable, dummySorter); + var resultMutable = mutable.slice(); + resultMutable.sort(dummySorter); + + TestUtils.assertJsonEqual(resultImmutable, resultMutable); + }); + }); - it("produces a sorted immutable array when provided with a sorter function", function() { - check(100, [ JSC.array(JSC.integer(4), JSC.any()) ], function(array) { - var immutable = Immutable(array); - var mutable = array.slice(); + it("returns the same array if it is already sorted", function() { + check(100, [JSC.array(JSC.integer(4), JSC.any())], function(array) { + var mutable = array.slice().sort(); + var immutable = Immutable(mutable); - var resultImmutable = Immutable.sortBy(immutable, dummySorter); - var resultMutable = mutable.slice(); - resultMutable.sort(dummySorter); + var resultImmutable = Immutable.sortBy(immutable); - TestUtils.assertJsonEqual(resultImmutable, resultMutable); - }); + assert.strictEqual(resultImmutable, immutable); + }); + }); }); - }); };