From c8d4025621e9e471a9584e01118ce31b47600f86 Mon Sep 17 00:00:00 2001 From: Kit Cambridge Date: Mon, 20 Feb 2012 12:21:36 -0700 Subject: [PATCH 1/3] Issue #484: `_.uniq()` should work with sparse arrays. --- test/arrays.js | 22 ++++++++++++++++++++++ underscore.js | 13 ++++++------- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/test/arrays.js b/test/arrays.js index 54cd9f8d2..ff430648d 100644 --- a/test/arrays.js +++ b/test/arrays.js @@ -89,6 +89,28 @@ $(document).ready(function() { var result = (function(){ return _.uniq(arguments); })(1, 2, 1, 3, 1, 4); equal(result.join(', '), '1, 2, 3, 4', 'works on an arguments object'); + + var list = []; + list[2] = list[3] = null; + list[8] = 2; + list[10] = 2; + list[11] = 5; + list[14] = 5; + list[16] = 8; + list[19] = 8; + list[26] = list[29] = undefined; + list[33] = "hi"; + + var result = _.uniq(list, true); + if (0 in [undefined]) { + // According to the JScript ES 3 spec, section 2.1.26, JScript 5.x (IE <= + // 8) treats `undefined` elements in arrays as elisions. + deepEqual(result, [null, 2, 5, 8, undefined, "hi"], "Works with sorted sparse arrays"); + equal(result.length, 6, "The resulting array should not be sparse"); + } else { + deepEqual(result, [null, 2, 5, 8, "hi"], "Works with sorted sparse arrays where `undefined` elements are elided"); + equal(result.length, 5, "The resulting array should not be sparse"); + } }); test("arrays: intersection", function() { diff --git a/underscore.js b/underscore.js index a283e55ff..2d3ccdfd6 100644 --- a/underscore.js +++ b/underscore.js @@ -371,16 +371,15 @@ // been sorted, you have the option of using a faster algorithm. // Aliased as `unique`. _.uniq = _.unique = function(array, isSorted, iterator) { - var initial = iterator ? _.map(array, iterator) : array; - var result = []; - _.reduce(initial, function(memo, el, i) { - if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) { - memo[memo.length] = el; - result[result.length] = array[i]; + var results = [], previous; + _.reduce(iterator ? _.map(array, iterator) : array, function (memo, value, index) { + if (array.length < 3 || isSorted ? _.last(memo) !== value || !memo.length : !_.include(memo, value)) { + memo.push(previous = value); + results.push(array[index]); } return memo; }, []); - return result; + return results; }; // Produce an array that contains the union: each distinct element from all of From 0285f47f7835fd62919d72cf2d399756f86a8044 Mon Sep 17 00:00:00 2001 From: Kit Cambridge Date: Mon, 20 Feb 2012 12:36:48 -0700 Subject: [PATCH 2/3] `_.uniq()`: Remove unused `previous` variable. --- underscore.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/underscore.js b/underscore.js index 2d3ccdfd6..9b366cb5f 100644 --- a/underscore.js +++ b/underscore.js @@ -371,10 +371,10 @@ // been sorted, you have the option of using a faster algorithm. // Aliased as `unique`. _.uniq = _.unique = function(array, isSorted, iterator) { - var results = [], previous; + var results = []; _.reduce(iterator ? _.map(array, iterator) : array, function (memo, value, index) { if (array.length < 3 || isSorted ? _.last(memo) !== value || !memo.length : !_.include(memo, value)) { - memo.push(previous = value); + memo.push(value); results.push(array[index]); } return memo; From 8808f7d531733a0e88d31f122ffc3568d1dfce96 Mon Sep 17 00:00:00 2001 From: Kit Cambridge Date: Tue, 21 Feb 2012 10:35:55 -0700 Subject: [PATCH 3/3] Un-golf `_.uniq()`. --- underscore.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/underscore.js b/underscore.js index 9b366cb5f..88da6e1d8 100644 --- a/underscore.js +++ b/underscore.js @@ -371,9 +371,12 @@ // been sorted, you have the option of using a faster algorithm. // Aliased as `unique`. _.uniq = _.unique = function(array, isSorted, iterator) { + var initial = iterator ? _.map(array, iterator) : array; var results = []; - _.reduce(iterator ? _.map(array, iterator) : array, function (memo, value, index) { - if (array.length < 3 || isSorted ? _.last(memo) !== value || !memo.length : !_.include(memo, value)) { + // The `isSorted` flag is irrelevant if the array only contains two elements. + if (array.length < 3) isSorted = true; + _.reduce(initial, function (memo, value, index) { + if (isSorted ? _.last(memo) !== value || !memo.length : !_.include(memo, value)) { memo.push(value); results.push(array[index]); }