diff --git a/fp/_mapping.js b/fp/_mapping.js index e8e763799..3679633fe 100644 --- a/fp/_mapping.js +++ b/fp/_mapping.js @@ -66,7 +66,8 @@ module.exports = { 'sortedIndexOf', 'sortedLastIndex', 'sortedLastIndexOf', 'sortedUniqBy', 'split', 'startsWith', 'subtract', 'sumBy', 'take', 'takeRight', 'takeRightWhile', 'takeWhile', 'tap', 'throttle', 'thru', 'times', 'truncate', 'union', 'uniqBy', - 'uniqWith', 'unset', 'unzipWith', 'without', 'wrap', 'xor', 'zip', 'zipObject' + 'uniqWith', 'unset', 'unzipWith', 'without', 'wrap', 'xor', 'zip', 'zipObject', + 'zipObjectDeep' ], 3:[ 'assignInWith', 'assignWith', 'clamp', 'differenceBy', 'differenceWith', diff --git a/lodash.js b/lodash.js index 95aef7960..8367d9244 100644 --- a/lodash.js +++ b/lodash.js @@ -1391,7 +1391,8 @@ * `toArray`, `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, * `unary`, `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, * `unset`, `unshift`, `unzip`, `unzipWith`, `values`, `valuesIn`, `without`, - * `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, `zipObject`, and `zipWith` + * `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, `zipObject`, `zipObjectDeep`, + * and `zipWith` * * The wrapper methods that are **not** chainable by default are: * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, @@ -3626,6 +3627,27 @@ return (result && result.length) ? baseUniq(result, iteratee, comparator) : []; } + /** + * This base implementation of `_.zipObject` which assigns values using `assignFunc`. + * + * @private + * @param {Array} props The property names. + * @param {Array} values The property values. + * @param {Function} assignFunc The function to assign values. + * @returns {Object} Returns the new object. + */ + function baseZipObject(props, values, assignFunc) { + var index = -1, + length = props.length, + valsLength = values.length, + result = {}; + + while (++index < length) { + assignFunc(result, props[index], index < valsLength ? values[index] : undefined); + } + return result; + } + /** * Creates a clone of `buffer`. * @@ -6908,19 +6930,29 @@ * @returns {Object} Returns the new object. * @example * - * _.zipObject(['fred', 'barney'], [30, 40]); - * // => { 'fred': 30, 'barney': 40 } + * _.zipObject(['a', 'b'], [1, 2]); + * // => { 'a': 1, 'b': 2 } */ function zipObject(props, values) { - var index = -1, - length = props ? props.length : 0, - valsLength = values ? values.length : 0, - result = {}; + return baseZipObject(props || [], values || [], assignValue); + } - while (++index < length) { - baseSet(result, props[index], index < valsLength ? values[index] : undefined); - } - return result; + /** + * This method is like `_.zipObject` except that it supports property paths. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} [props=[]] The property names. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]); + * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } } + */ + function zipObjectDeep(props, values) { + return baseZipObject(props || [], values || [], baseSet); } /** @@ -14016,6 +14048,7 @@ lodash.xorWith = xorWith; lodash.zip = zip; lodash.zipObject = zipObject; + lodash.zipObjectDeep = zipObjectDeep; lodash.zipWith = zipWith; // Add aliases. diff --git a/test/test.js b/test/test.js index 605125d92..8e7b6ed33 100644 --- a/test/test.js +++ b/test/test.js @@ -22391,55 +22391,57 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.zipObject'); + QUnit.module('zipObject methods'); - (function() { - var object = { 'barney': 36, 'fred': 40 }, - array = [['barney', 36], ['fred', 40]]; + lodashStable.each(['zipObject', 'zipObjectDeep'], function(methodName) { + var func = _[methodName], + array = [['barney', 36], ['fred', 40]], + object = { 'barney': 36, 'fred': 40 }, + isDeep = methodName == 'zipObjectDeep'; - QUnit.test('should zip together key/value arrays into an object', function(assert) { + QUnit.test('`_.' + methodName + '` should zip together key/value arrays into an object', function(assert) { assert.expect(1); - var actual = _.zipObject(['barney', 'fred'], [36, 40]); + var actual = func(['barney', 'fred'], [36, 40]); assert.deepEqual(actual, object); }); - QUnit.test('should ignore extra `values`', function(assert) { + QUnit.test('`_.' + methodName + '` should ignore extra `values`', function(assert) { assert.expect(1); - assert.deepEqual(_.zipObject(['a'], [1, 2]), { 'a': 1 }); + assert.deepEqual(func(['a'], [1, 2]), { 'a': 1 }); }); - QUnit.test('should assign `undefined` values for extra `keys`', function(assert) { + QUnit.test('`_.' + methodName + '` should assign `undefined` values for extra `keys`', function(assert) { assert.expect(1); - assert.deepEqual(_.zipObject(['a', 'b'], [1]), { 'a': 1, 'b': undefined }); + assert.deepEqual(func(['a', 'b'], [1]), { 'a': 1, 'b': undefined }); }); - QUnit.test('should support deep paths', function(assert) { + QUnit.test('`_.' + methodName + '` should ' + (isDeep ? '' : 'not ') + 'support deep paths', function(assert) { assert.expect(2); - lodashStable.each(['a.b.c', ['a', 'b', 'c']], function(path) { - var actual = _.zipObject([path], [1]); - assert.deepEqual(actual, { 'a': { 'b': { 'c': 1 } } }); + lodashStable.each(['a.b.c', ['a', 'b', 'c']], function(path, index) { + var expected = isDeep ? ({ 'a': { 'b': { 'c': 1 } } }) : (index ? { 'a,b,c': 1 } : { 'a.b.c': 1 }); + assert.deepEqual(func([path], [1]), expected); }); }); - QUnit.test('should work in a lazy sequence', function(assert) { + QUnit.test('`_.' + methodName + '` should work in a lazy sequence', function(assert) { assert.expect(1); if (!isNpm) { var values = lodashStable.range(LARGE_ARRAY_SIZE), props = lodashStable.map(values, function(value) { return 'key' + value; }), - actual = _(props).zipObject(values).map(square).filter(isEven).take().value(); + actual = _(props)[methodName](values).map(square).filter(isEven).take().value(); - assert.deepEqual(actual, _.take(_.filter(_.map(_.zipObject(props, values), square), isEven))); + assert.deepEqual(actual, _.take(_.filter(_.map(func(props, values), square), isEven))); } else { skipTest(assert); } }); - }()); + }); /*--------------------------------------------------------------------------*/ @@ -23376,7 +23378,7 @@ var acceptFalsey = lodashStable.difference(allMethods, rejectFalsey); QUnit.test('should accept falsey arguments', function(assert) { - assert.expect(287); + assert.expect(288); var emptyArrays = lodashStable.map(falsey, alwaysEmptyArray);