Skip to content
This repository was archived by the owner on Mar 12, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,36 @@ Immutable.from([1, 2, 3]);
Immutable([1, 2, 3])
```

## Immutable.sortBy

As you may have read, you cannot call `Immutable([/* elements */]).sort()` without
receiving an error because of the mutable nature of the sort method.

However with `sortBy` you will be able to sort immutable arrays of objects or just plain
types passing an attribute function. You will have two types of sorting, ascendant or
descendant order (based on [Lodash](https://lodash.com/docs/4.17.15#sortBy)
and [Ramda](https://ramdajs.com/docs/#sortBy) behaviors).

The order types are two constants provided as `Immutable.OrderTypes`, which are:
- `DESC`: Descendant order.
- `ASC`: Ascendant order. It is used by default if you don't provide one.

```javascript
var identityFn = function(x) { return x };
var array = Immutable([3, 4, 1, 2]);

var sortedAsc = Immutable.sortBy(array, identityFn);
// sortedAsc will be Immutable([1, 2, 3, 4])

var sortedDesc = Immutable.sortBy(array, identityFn, Immutable.OrderTypes.DESC); // or just 'DESC'
// sortedAsc will be Immutable([4, 3, 2, 1])

var people = Immutable([ { age: 17 }, { age: 16 }, { age: 40 } ]);
var byAge = function(obj) { return obj.age; };
var sortedAscByAge = Immutable.sortBy(people, byAge);
// sortedByAge will be Immutable([ { age: 16 }, { age: 17 }, { age: 40 } ])
```

## Immutable Array

Like a regular Array, but immutable! You can construct these by passing
Expand Down
41 changes: 41 additions & 0 deletions src/seamless-immutable.js
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,45 @@ function immutableInit(config) {
return staticWrapper;
}

var OrderTypes = {
ASC: 'ASC',
DESC: 'DESC'
};

function basicSorter(a, b) {
return isEqual(a, b) ? 0 : (a > b ? 1 : (-1));
}

function sortBy(attribute, ordering) {
var orderType = ordering || OrderTypes.ASC; // Default param simulation on ES5
var self = this;
if (!Array.isArray(self)) {
throw new TypeError('The first argument must be an array, you got ' + typeof self);
} else {
if (typeof attribute !== 'function') {
throw new TypeError('The attribute must be a function that returns the value used to order the array. You got ' + typeof attribute);
} else {
var mutableArray = asMutableArray.call(self); // No need to be deep, because sort will only modify the temporary array
mutableArray.sort(function (a, b) {
var finalOrder = OrderTypes.hasOwnProperty(orderType) && (orderType || OrderTypes.ASC);
var firstElement = !isObject(a) ? a : attribute(a);
var secondElement = !isObject(a) ? b : attribute(b);
return finalOrder === OrderTypes.ASC ?
basicSorter(firstElement, secondElement)
: basicSorter(secondElement, firstElement);
});
var isAlreadySorted = mutableArray.slice(0).reduce(function (sorted, current, i, array) {
if (!sorted) {
array.splice(1); // Reduce early exit hack, i refuse to modify variables
} else {
return sorted && isEqual(current, self[i]);
}
}, true);
return isAlreadySorted ? self : makeImmutableArray(mutableArray);
}
}
}

// Export the library
Immutable.from = Immutable;
Immutable.isImmutable = isImmutable;
Expand All @@ -728,6 +767,8 @@ function immutableInit(config) {
Immutable.getIn = toStatic(getIn);
Immutable.flatMap = toStatic(flatMap);
Immutable.asObject = toStatic(asObject);
Immutable.sortBy = toStatic(sortBy);
Immutable.OrderTypes = OrderTypes;
if (!globalConfig.use_static) {
Immutable.static = immutableInit({
use_static: true
Expand Down
4 changes: 3 additions & 1 deletion test/ImmutableArray.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ var testAsObject = require("./ImmutableArray/test-asObject.js");
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 testGetIn = require("./ImmutableArray/test-getIn.js");
var testSortBy = require("./ImmutableArray/test-sortBy.js")
var devBuild = require("../seamless-immutable.development.js");
var prodBuild = require("../seamless-immutable.production.min.js");
var getTestUtils = require("./TestUtils.js");
Expand All @@ -25,6 +26,7 @@ var getTestUtils = require("./TestUtils.js");
testSet(config);
testUpdate(config);
testGetIn(config);
testSortBy(config);
});
});
});
60 changes: 60 additions & 0 deletions test/ImmutableArray/test-sortBy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
var JSC = require("jscheck");
var assert = require("chai").assert;
var _ = require("lodash");
var getTestUtils = require("../TestUtils.js");

module.exports = function(config) {
var Immutable = config.implementation;
var TestUtils = getTestUtils(Immutable);
var check = TestUtils.check;
var identityFn = function (x) { return x; }

describe("#sortBy", function() {
it('should returns an immutable array', function() {
var array = Immutable(['foo', 'foo2', 'bar', 'bar2']);
var sorted = Immutable.sortBy(array, identityFn);
assert.equal(Immutable.isImmutable(sorted), true);
})

it('should returns the same array when it is already sorted', function() {
var array = Immutable([1, 2, 3, 4]);
var sorted = Immutable.sortBy(array, identityFn)
assert.equal(sorted, array)
})

it('should order the array in an ascendant way by default', function() {
var array = Immutable([3, 4, 1, 2]);
var sorted = Immutable.sortBy(array, identityFn);
TestUtils.assertJsonEqual(sorted, Immutable([1, 2, 3, 4]));
})

it('should order the array in a descendant way', function() {
var array = Immutable([3, 4, 1, 2]);
var sorted = Immutable.sortBy(array, identityFn, Immutable.OrderTypes.DESC);
TestUtils.assertJsonEqual(sorted, Immutable([4, 3, 2, 1]));
})

it('should throw an error when you pass in the attribute argument with a type different to a function', function() {
var array = Immutable([{ age: 1 }, { age: 2 }]);
var fnWithError = function() {
Immutable.sortBy(array, 'invalid');
}
assert.throws(fnWithError, 'The attribute must be a function that returns the value used to order the array. You got string')
})

it('should throw an error if you pass something different to an array as the array param', function() {
var fnWithError = function() {
Immutable.sortBy({}, 'invalid');
}
assert.throws(fnWithError, 'The first argument must be an array, you got object');
})

it('should order an array with object by attribute correctly', function() {
var fn = function(person) { return person.age }
var people = Immutable([{ name: 'Josh', age: 34 }, { name: 'Melanie', age: 18 }, { name: 'Mark', age: 44 }]);
var sortedByAge = Immutable.sortBy(people, fn, Immutable.OrderTypes.ASC);
var expected = Immutable([{ name: 'Melanie', age: 18 }, { name: 'Josh', age: 34 }, { name: 'Mark', age: 44 }]);
TestUtils.assertJsonEqual(sortedByAge, expected);
})
});
};