From e3c218092c374a5ce7f232d4ec6fdc63962dcab5 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Tue, 15 Apr 2014 01:17:55 -0700 Subject: [PATCH] Add `_.findWhere` as its own method. --- lodash.js | 52 +++++++++++++++++++++++++++------- test/test.js | 80 ++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 98 insertions(+), 34 deletions(-) diff --git a/lodash.js b/lodash.js index a0f8fbab9..d4676f9c5 100644 --- a/lodash.js +++ b/lodash.js @@ -3905,7 +3905,7 @@ * * @static * @memberOf _ - * @alias detect, findWhere + * @alias detect * @category Collections * @param {Array|Object|string} collection The collection to search. * @param {Function|Object|string} [predicate=identity] The function called @@ -3968,6 +3968,35 @@ return baseFind(collection, predicate, baseEachRight); } + + /** + * Performs a deep comparison between each element in `collection` and the + * source object, returning the first element that has equivalent property + * values. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object|string} collection The collection to search. + * @param {Object} source The object of property values to match. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * var characters = [ + * { 'name': 'barney', 'age': 36, 'employer': 'slate' }, + * { 'name': 'fred', 'age': 40, 'employer': 'slate' } + * ]; + * + * _.findWhere(characters, { 'employer': 'slate' }); + * // => { 'name': 'barney', 'age': 36, 'employer': 'slate' } + * + * _.findWhere(characters, { 'age': 40 }); + * // => { 'name': 'fred', 'age': 40, 'employer': 'slate' } + */ + function findWhere(collection, source) { + return find(collection, isObject(source) ? source : {}); + } + /** * Iterates over elements of a collection executing the callback for each * element. The callback is bound to `thisArg` and invoked with three arguments; @@ -4809,21 +4838,24 @@ * @static * @memberOf _ * @category Collections - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Object} source The object of property values to filter by. + * @param {Array|Object|string} collection The collection to search. + * @param {Object} source The object of property values to match. * @returns {Array} Returns the new filtered array. * @example * * var characters = [ - * { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }, - * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] } + * { 'name': 'barney', 'age': 36, 'employer': 'slate', 'pets': ['hoppy'] }, + * { 'name': 'fred', 'age': 40, 'employer': 'slate', 'pets': ['baby puss', 'dino'] } * ]; * - * _.where(characters, { 'age': 36 }); - * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }] + * _.pluck(_.where(characters, { 'age': 36 }), 'name'); + * // => ['barney'] * - * _.where(characters, { 'pets': ['dino'] }); - * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }] + * _.pluck(_.where(characters, { 'pets': ['dino'] }), 'name'); + * // => ['fred'] + * + * _.pluck(_.where(characters, { 'employer': 'slate' }), 'name'); + * // => ['barney', 'fred'] */ function where(collection, source) { return filter(collection, isObject(source) ? source : {}); @@ -8365,6 +8397,7 @@ lodash.findLast = findLast; lodash.findLastIndex = findLastIndex; lodash.findLastKey = findLastKey; + lodash.findWhere = findWhere; lodash.has = has; lodash.identity = identity; lodash.indexOf = indexOf; @@ -8418,7 +8451,6 @@ lodash.all = every; lodash.any = some; lodash.detect = find; - lodash.findWhere = find; lodash.foldl = reduce; lodash.foldr = reduceRight; lodash.include = contains; diff --git a/test/test.js b/test/test.js index c0ac31d89..5b6fcad80 100644 --- a/test/test.js +++ b/test/test.js @@ -2652,9 +2652,8 @@ }); } if (methodName == 'find') { - test('should be aliased', 2, function() { + test('should be aliased', 1, function() { strictEqual(_.detect, func); - strictEqual(_.findWhere, func); }); } }()); @@ -2662,6 +2661,39 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.findWhere'); + + (function() { + var objects = [ + { 'a': 1 }, + { 'a': 1 }, + { 'a': 1, 'b': 2 }, + { 'a': 2, 'b': 2 }, + { 'a': 3 } + ]; + + test('should filter by `source` properties', 6, function() { + strictEqual(_.findWhere(objects, { 'a': 1 }), objects[0]); + strictEqual(_.findWhere(objects, { 'a': 2 }), objects[3]); + strictEqual(_.findWhere(objects, { 'a': 3 }), objects[4]); + strictEqual(_.findWhere(objects, { 'b': 1 }), undefined); + strictEqual(_.findWhere(objects, { 'b': 2 }), objects[2]); + strictEqual(_.findWhere(objects, { 'a': 1, 'b': 2 }), objects[2]); + }); + + test('should match all elements when provided an empty `source`', 1, function() { + var expected = _.map(empties, _.constant(true)); + + var actual = _.map(empties, function(value) { + return _.findWhere(objects, value) === objects[0]; + }); + + deepEqual(actual, expected); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.first'); (function() { @@ -9528,7 +9560,7 @@ QUnit.module('lodash.where'); (function() { - var array = [ + var objects = [ { 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }, @@ -9536,22 +9568,22 @@ { 'a': 3 } ]; - test('should filter by properties', 6, function() { - deepEqual(_.where(array, { 'a': 1 }), [{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }]); - deepEqual(_.where(array, { 'a': 2 }), [{ 'a': 2, 'b': 2 }]); - deepEqual(_.where(array, { 'a': 3 }), [{ 'a': 3 }]); - deepEqual(_.where(array, { 'b': 1 }), []); - deepEqual(_.where(array, { 'b': 2 }), [{ 'a': 1, 'b': 2 }, { 'a': 2, 'b': 2 }]); - deepEqual(_.where(array, { 'a': 1, 'b': 2 }), [{ 'a': 1, 'b': 2 }]); + test('should filter by `source` properties', 6, function() { + deepEqual(_.where(objects, { 'a': 1 }), [{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }]); + deepEqual(_.where(objects, { 'a': 2 }), [{ 'a': 2, 'b': 2 }]); + deepEqual(_.where(objects, { 'a': 3 }), [{ 'a': 3 }]); + deepEqual(_.where(objects, { 'b': 1 }), []); + deepEqual(_.where(objects, { 'b': 2 }), [{ 'a': 1, 'b': 2 }, { 'a': 2, 'b': 2 }]); + deepEqual(_.where(objects, { 'a': 1, 'b': 2 }), [{ 'a': 1, 'b': 2 }]); }); - test('should not filter by inherited properties', 1, function() { + test('should not filter by inherited `source` properties', 1, function() { function Foo() {} Foo.prototype = { 'a': 2 }; - var properties = new Foo; - properties.b = 2; - deepEqual(_.where(array, properties), [{ 'a': 1, 'b': 2 }, { 'a': 2, 'b': 2 }]); + var source = new Foo; + source.b = 2; + deepEqual(_.where(objects, source), [{ 'a': 1, 'b': 2 }, { 'a': 2, 'b': 2 }]); }); test('should filter by problem JScript properties (test in IE < 9)', 1, function() { @@ -9570,11 +9602,11 @@ }); test('should match all elements when provided an empty `source`', 1, function() { - var expected = _.map(empties, _.constant(array)); + var expected = _.map(empties, _.constant(objects)); var actual = _.map(empties, function(value) { - var result = _.where(array, value); - return result !== array && result; + var result = _.where(objects, value); + return result !== objects && result; }); deepEqual(actual, expected); @@ -9595,18 +9627,18 @@ deepEqual(_.where(collection, { 'a': [2] }), expected); }); - test('should handle `properties` with `undefined` values', 4, function() { - var properties = { 'b': undefined }; - deepEqual(_.where([{ 'a': 1 }, { 'a': 1, 'b': 1 }], properties), []); + test('should handle a `source` with `undefined` values', 4, function() { + var source = { 'b': undefined }; + deepEqual(_.where([{ 'a': 1 }, { 'a': 1, 'b': 1 }], source), []); var object = { 'a': 1, 'b': undefined }; - deepEqual(_.where([object], properties), [object]); + deepEqual(_.where([object], source), [object]); - properties = { 'a': { 'c': undefined } }; - deepEqual(_.where([{ 'a': { 'b': 1 } }, { 'a':{ 'b':1 , 'c': 1 } }], properties), []); + source = { 'a': { 'c': undefined } }; + deepEqual(_.where([{ 'a': { 'b': 1 } }, { 'a':{ 'b':1 , 'c': 1 } }], source), []); object = { 'a': { 'b': 1, 'c': undefined } }; - deepEqual(_.where([object], properties), [object]); + deepEqual(_.where([object], source), [object]); }); }());