diff --git a/.eslintrc b/.eslintrc index 2c46d63de..bc7da0540 100644 --- a/.eslintrc +++ b/.eslintrc @@ -20,7 +20,7 @@ "no-floating-decimal": 2, "no-inner-declarations": 2, "no-lonely-if": 1, - "no-nested-ternary": 2, + "no-nested-ternary": 0, "no-new-object": 0, "no-new-func": 0, "no-underscore-dangle": 0, diff --git a/test/arrays.js b/test/arrays.js index 5706a6442..2799011f4 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -136,6 +136,17 @@ equal(_.sortedIndex(array, 2147483648), 2147483648, 'should work with large indexes'); }); + test('sortedIndex conforms to sortBy (#1768)', function() { + var sorted = _([{a: NaN}, {a: NaN}, {a: void 0}, {a: 0}, {a: 1}, {a: 2}, {a: 3}, {a: '4'}, {a: 'foo'}]) + .sortBy('a'); + _.each([0, 1, 2, 3, '4', 'foo'], function(val) { + equal(_.sortedIndex(sorted, {a: val}, 'a'), _.findIndex(sorted, {a: val}), 'For val: ' + val); + }); + + sorted = _.sortBy([undefined, 1, undefined, 2]); + equal(_.sortedIndex(sorted, undefined, _.identity), 2); + }); + test('uniq', function() { var list = [1, 2, 1, 3, 1, 4]; deepEqual(_.uniq(list), [1, 2, 3, 4], 'can find the unique values of an unsorted array'); diff --git a/test/utility.js b/test/utility.js index 0330f0dbe..fd5338844 100644 --- a/test/utility.js +++ b/test/utility.js @@ -78,6 +78,40 @@ ok(diff <= 0 && diff > -5, 'Produces the correct time in milliseconds');//within 5ms }); + test('comparator', function() { + _.each([ + [2, 1], + [2, '1'], + ['2', 1], + [1.0001, 1], + [1, null], + [null, -1], + [void 0, null], + [void 0, 5], + [NaN, 'something'], + ['b', 'a'], + [-5, '-6.05'] + ], function(vals) { + var a = vals[0], b = vals[1]; + equal(_.comparator(a, b), 1, '\'' + a + '\' >= \'' + b + '\''); + equal(_.comparator(b, a), -1, '\'' + b + '\' <= \'' + a + '\''); + }); + + _.each([ + [0, 0], + [null, 0], + [void 0, void 0], + [NaN, NaN], + [1, {valueOf: _.constant(1)}], + [1, '1'], + ['zap', 'zap'] + ], function(vals) { + var a = vals[0], b = vals[1]; + equal(_.comparator(a, b), 0, '\'' + a + '\' == \'' + b + '\''); + equal(_.comparator(b, a), 0, '\'' + b + '\' == \'' + a + '\''); + }); + }); + test('uniqueId', function() { var ids = [], i = 0; while (i++ < 100) ids.push(_.uniqueId()); diff --git a/underscore.js b/underscore.js index 8dc638003..c92146344 100644 --- a/underscore.js +++ b/underscore.js @@ -397,13 +397,7 @@ criteria: iteratee(value, index, list) }; }).sort(function(left, right) { - var a = left.criteria; - var b = right.criteria; - if (a !== b) { - if (a > b || a === void 0) return 1; - if (a < b || b === void 0) return -1; - } - return left.index - right.index; + return _.comparator(left.criteria, right.criteria) || left.index - right.index; }), 'value'); }; @@ -675,7 +669,7 @@ var low = 0, high = array.length; while (low < high) { var mid = Math.floor((low + high) / 2); - if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; + if (_.comparator(iteratee(array[mid]), value) < 0) low = mid + 1; else high = mid; } return low; }; @@ -1299,6 +1293,18 @@ }; }; + // Default internal comparator for determining whether a is greater (1), + // equal (0) or less than (-1) some object b + _.comparator = function(a, b) { + if (a === b) return 0; + var isAComparable = a >= a, isBComparable = b >= b; + if (isAComparable || isBComparable) { + if (isAComparable && !isBComparable) return -1; + if (isBComparable && !isAComparable) return 1; + } + return a > b ? 1 : (b > a) ? -1 : 0; + }; + // Run a function **n** times. _.times = function(n, iteratee, context) { var accum = Array(Math.max(0, n));