diff --git a/lodash.js b/lodash.js index f6855af5c..b362ee900 100644 --- a/lodash.js +++ b/lodash.js @@ -776,21 +776,6 @@ return -1; } - /** - * The base implementation of `_.pairs` and `_.pairsIn` which creates an array - * of key-value pairs for `object` corresponding to the property names of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the new array of key-value pairs. - */ - function basePairs(object, props) { - return arrayMap(props, function(key) { - return [key, object[key]]; - }); - } - /** * The base implementation of `_.reduce` and `_.reduceRight`, without support * for callback shorthands, which iterates over `collection` using the provided @@ -874,6 +859,21 @@ return result; } + /** + * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array + * of key-value pairs for `object` corresponding to the property names of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the new array of key-value pairs. + */ + function baseToPairs(object, props) { + return arrayMap(props, function(key) { + return [key, object[key]]; + }); + } + /** * The base implementation of `_.unary` without support for storing wrapper metadata. * @@ -1494,21 +1494,21 @@ * `differenceBy`, `differenceWith`, `drop`, `dropRight`, `dropRightWhile`, * `dropWhile`, `fill`, `filter`, `flatten`, `flattenDeep`, `flip`, `flow`, * `flowRight`, `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, - * `forOwnRight`, `functions`, `functionsIn`, `groupBy`, `initial`, + * `forOwnRight`, `fromPairs`, `functions`, `functionsIn`, `groupBy`, `initial`, * `intersection`, `intersectionBy`, `intersectionWith`, invert`, `invoke`, * `iteratee`, `keyBy`, `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, * `matches`, `matchesProperty`, `memoize`, `merge`, `mergeWith`, `method`, * `methodOf`, `mixin`, `modArgs`, `modArgsSet', `negate`, `nthArg`, `omit`, - * `omitBy`, `once`, `over`, `overEvery`, `overSome`, `pairs`, `pairsIn`, - * `partial`, `partialRight`, `partition`, `pick`, `pickBy`, `plant`, `property`, - * `propertyOf`, `pull`, `pullAll`, `pullAllBy`, `pullAt`, `push`, `range`, - * `rearg`, `reject`, `remove`, `rest`, `reverse`, `sampleSize`, `set`, - * `setWith`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByOrder`, `splice`, - * `spread`, `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, - * `tap`, `throttle`, `thru`, `toArray`, `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` + * `omitBy`, `once`, `over`, `overEvery`, `overSome`, `partial`, `partialRight`, + * `partition`, `pick`, `pickBy`, `plant`, `property`, `propertyOf`, `pull`, + * `pullAll`, `pullAllBy`, `pullAt`, `push`, `range`, `rearg`, `reject`, + * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, + * `slice`, `sort`, `sortBy`, `sortByOrder`, `splice`, `spread`, `tail`, + * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `tap`, `throttle`, + * `thru`, `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`, and `zipWith` * * The wrapper methods that are **not** chainable by default are: * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, @@ -4591,7 +4591,7 @@ * @returns {Array} Returns the match data of `object`. */ function getMatchData(object) { - var result = pairs(object), + var result = toPairs(object), length = result.length; while (length--) { @@ -5585,6 +5585,45 @@ return length ? baseFlatten(array, true) : []; } + /** + * The inverse of `_.toPairs`; this method returns an object composed from arrays + * of property names and values. Provide either a single two dimensional array, + * e.g. `[[key1, value1], [key2, value2]]` or two arrays, one of property names + * and one of corresponding values. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} props The property names. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.fromPairs([['fred', 30], ['barney', 40]]); + * // => { 'fred': 30, 'barney': 40 } + * + * _.fromPairs(['fred', 'barney'], [30, 40]); + * // => { 'fred': 30, 'barney': 40 } + */ + function fromPairs(props, values) { + var index = -1, + length = props ? props.length : 0, + result = {}; + + if (length && !values && !isArray(props[0])) { + values = []; + } + while (++index < length) { + var key = props[index]; + if (values) { + baseSet(result, key, values[index]); + } else if (key) { + baseSet(result, key[0], key[1]); + } + } + return result; + } + /** * Gets the first element of `array`. * @@ -6706,45 +6745,6 @@ */ var zip = rest(unzip); - /** - * The inverse of `_.pairs`; this method returns an object composed from arrays - * of property names and values. Provide either a single two dimensional array, - * e.g. `[[key1, value1], [key2, value2]]` or two arrays, one of property names - * and one of corresponding values. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} props The property names. - * @param {Array} [values=[]] The property values. - * @returns {Object} Returns the new object. - * @example - * - * _.zipObject([['fred', 30], ['barney', 40]]); - * // => { 'fred': 30, 'barney': 40 } - * - * _.zipObject(['fred', 'barney'], [30, 40]); - * // => { 'fred': 30, 'barney': 40 } - */ - function zipObject(props, values) { - var index = -1, - length = props ? props.length : 0, - result = {}; - - if (length && !values && !isArray(props[0])) { - values = []; - } - while (++index < length) { - var key = props[index]; - if (values) { - baseSet(result, key, values[index]); - } else if (key) { - baseSet(result, key[0], key[1]); - } - } - return result; - } - /** * This method is like `_.zip` except that it accepts `iteratee` to specify * how grouped values should be combined. The iteratee is invoked with four @@ -11110,54 +11110,6 @@ }); } - /** - * Creates an array of own enumerable key-value pairs for `object`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the new array of key-value pairs. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.pairs(new Foo); - * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed) - */ - function pairs(object) { - return basePairs(object, keys(object)); - } - - /** - * Creates an array of own and inherited enumerable key-value pairs for `object`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the new array of key-value pairs. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.pairsIn(new Foo); - * // => [['a', 1], ['b', 2], ['c', 1]] (iteration order is not guaranteed) - */ - function pairsIn(object) { - return basePairs(object, keysIn(object)); - } - /** * Creates an object composed of the picked `object` properties. * @@ -11299,6 +11251,54 @@ return object == null ? object : baseSet(object, path, value, customizer); } + /** + * Creates an array of own enumerable key-value pairs for `object`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the new array of key-value pairs. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.toPairs(new Foo); + * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed) + */ + function toPairs(object) { + return baseToPairs(object, keys(object)); + } + + /** + * Creates an array of own and inherited enumerable key-value pairs for `object`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the new array of key-value pairs. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.toPairsIn(new Foo); + * // => [['a', 1], ['b', 2], ['c', 1]] (iteration order is not guaranteed) + */ + function toPairsIn(object) { + return baseToPairs(object, keysIn(object)); + } + /** * An alternative to `_.reduce`; this method transforms `object` to a new * `accumulator` object which is the result of running each of its own enumerable @@ -13634,6 +13634,7 @@ lodash.flip = flip; lodash.flow = flow; lodash.flowRight = flowRight; + lodash.fromPairs = fromPairs; lodash.functions = functions; lodash.functionsIn = functionsIn; lodash.groupBy = groupBy; @@ -13668,8 +13669,6 @@ lodash.over = over; lodash.overEvery = overEvery; lodash.overSome = overSome; - lodash.pairs = pairs; - lodash.pairsIn = pairsIn; lodash.partial = partial; lodash.partialRight = partialRight; lodash.partition = partition; @@ -13706,6 +13705,8 @@ lodash.throttle = throttle; lodash.thru = thru; lodash.toArray = toArray; + lodash.toPairs = toPairs; + lodash.toPairsIn = toPairsIn; lodash.toPath = toPath; lodash.toPlainObject = toPlainObject; lodash.transform = transform; @@ -13728,7 +13729,6 @@ lodash.xorBy = xorBy; lodash.xorWith = xorWith; lodash.zip = zip; - lodash.zipObject = zipObject; lodash.zipWith = zipWith; // Add aliases. diff --git a/test/test.js b/test/test.js index 515a721c8..2cf3d2e88 100644 --- a/test/test.js +++ b/test/test.js @@ -5969,6 +5969,93 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.fromPairs'); + + (function() { + var object = { 'barney': 36, 'fred': 40 }, + array = [['barney', 36], ['fred', 40]]; + + QUnit.test('should skip falsey elements in a given two dimensional array', function(assert) { + assert.expect(1); + + var actual = _.fromPairs(array.concat(falsey)); + assert.deepEqual(actual, object); + }); + + QUnit.test('should zip together key/value arrays into an object', function(assert) { + assert.expect(1); + + var actual = _.fromPairs(['barney', 'fred'], [36, 40]); + assert.deepEqual(actual, object); + }); + + QUnit.test('should ignore extra `values`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.fromPairs(['a'], [1, 2]), { 'a': 1 }); + }); + + QUnit.test('should accept a two dimensional array', function(assert) { + assert.expect(1); + + var actual = _.fromPairs(array); + assert.deepEqual(actual, object); + }); + + QUnit.test('should not assume `keys` is two dimensional if `values` is not provided', function(assert) { + assert.expect(1); + + var actual = _.fromPairs(['barney', 'fred']); + assert.deepEqual(actual, { 'barney': undefined, 'fred': undefined }); + }); + + QUnit.test('should accept a falsey `array` argument', function(assert) { + assert.expect(1); + + var expected = lodashStable.map(falsey, lodashStable.constant({})); + + var actual = lodashStable.map(falsey, function(array, index) { + try { + return index ? _.fromPairs(array) : _.fromPairs(); + } catch (e) {} + }); + + assert.deepEqual(actual, expected); + }); + + QUnit.test('should support deep paths', function(assert) { + assert.expect(1); + + var actual = _.fromPairs(['a.b.c'], [1]); + assert.deepEqual(actual, { 'a': { 'b': { 'c': 1 } } }); + }); + + QUnit.test('should support consuming the return value of `_.toPairs`', function(assert) { + assert.expect(1); + + assert.deepEqual(_.fromPairs(_.toPairs(object)), object); + }); + + QUnit.test('should work in a lazy chain sequence', function(assert) { + assert.expect(1); + + if (!isNpm) { + var array = lodashStable.times(LARGE_ARRAY_SIZE, function(index) { + return ['key' + index, index]; + }); + + var actual = _(array).fromPairs().map(square).filter(isEven).take().value(); + + assert.deepEqual(actual, _.take(_.filter(_.map(_.fromPairs(array), square), isEven))); + } + else { + skipTest(assert); + } + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.functions'); (function() { @@ -13891,7 +13978,7 @@ assert.strictEqual(object.over(), false); }); }()); - + /*--------------------------------------------------------------------------*/ QUnit.module('lodash.overSome'); @@ -14125,34 +14212,6 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.pairs'); - - (function() { - QUnit.test('should create a two dimensional array of key-value pairs', function(assert) { - assert.expect(1); - - var object = { 'a': 1, 'b': 2 }; - assert.deepEqual(_.pairs(object), [['a', 1], ['b', 2]]); - }); - - QUnit.test('should work with an object that has a `length` property', function(assert) { - assert.expect(1); - - var object = { '0': 'a', '1': 'b', 'length': 2 }; - assert.deepEqual(_.pairs(object), [['0', 'a'], ['1', 'b'], ['length', 2]]); - }); - - QUnit.test('should work with strings', function(assert) { - assert.expect(2); - - lodashStable.each(['xo', Object('xo')], function(string) { - assert.deepEqual(_.pairs(string), [['0', 'x'], ['1', 'o']]); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.parseInt'); (function() { @@ -17241,7 +17300,7 @@ new Pair(undefined, 5, 1), new Pair(undefined, 6, 1) ]; - var stableObject = _.zipObject('abcdefghijklmnopqrst'.split(''), stableArray); + var stableObject = lodashStable.zipObject('abcdefghijklmnopqrst'.split(''), stableArray); QUnit.test('`_.' + methodName + '` should sort mutliple properties in ascending order', function(assert) { assert.expect(1); @@ -19486,7 +19545,7 @@ assert.deepEqual(actual, lodashStable.map(array.slice(1), String)); - var object = _.zipObject(lodashStable.times(LARGE_ARRAY_SIZE, function(index) { + var object = lodashStable.zipObject(lodashStable.times(LARGE_ARRAY_SIZE, function(index) { return ['key' + index, index]; })); @@ -19859,6 +19918,34 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.toPairs'); + + (function() { + QUnit.test('should create a two dimensional array of key-value pairs', function(assert) { + assert.expect(1); + + var object = { 'a': 1, 'b': 2 }; + assert.deepEqual(_.toPairs(object), [['a', 1], ['b', 2]]); + }); + + QUnit.test('should work with an object that has a `length` property', function(assert) { + assert.expect(1); + + var object = { '0': 'a', '1': 'b', 'length': 2 }; + assert.deepEqual(_.toPairs(object), [['0', 'a'], ['1', 'b'], ['length', 2]]); + }); + + QUnit.test('should work with strings', function(assert) { + assert.expect(2); + + lodashStable.each(['xo', Object('xo')], function(string) { + assert.deepEqual(_.toPairs(string), [['0', 'x'], ['1', 'o']]); + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.toPath'); (function() { @@ -21322,93 +21409,6 @@ /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.zipObject'); - - (function() { - var object = { 'barney': 36, 'fred': 40 }, - array = [['barney', 36], ['fred', 40]]; - - QUnit.test('should skip falsey elements in a given two dimensional array', function(assert) { - assert.expect(1); - - var actual = _.zipObject(array.concat(falsey)); - assert.deepEqual(actual, object); - }); - - QUnit.test('should zip together key/value arrays into an object', function(assert) { - assert.expect(1); - - var actual = _.zipObject(['barney', 'fred'], [36, 40]); - assert.deepEqual(actual, object); - }); - - QUnit.test('should ignore extra `values`', function(assert) { - assert.expect(1); - - assert.deepEqual(_.zipObject(['a'], [1, 2]), { 'a': 1 }); - }); - - QUnit.test('should accept a two dimensional array', function(assert) { - assert.expect(1); - - var actual = _.zipObject(array); - assert.deepEqual(actual, object); - }); - - QUnit.test('should not assume `keys` is two dimensional if `values` is not provided', function(assert) { - assert.expect(1); - - var actual = _.zipObject(['barney', 'fred']); - assert.deepEqual(actual, { 'barney': undefined, 'fred': undefined }); - }); - - QUnit.test('should accept a falsey `array` argument', function(assert) { - assert.expect(1); - - var expected = lodashStable.map(falsey, lodashStable.constant({})); - - var actual = lodashStable.map(falsey, function(array, index) { - try { - return index ? _.zipObject(array) : _.zipObject(); - } catch (e) {} - }); - - assert.deepEqual(actual, expected); - }); - - QUnit.test('should support deep paths', function(assert) { - assert.expect(1); - - var actual = _.zipObject(['a.b.c'], [1]); - assert.deepEqual(actual, { 'a': { 'b': { 'c': 1 } } }); - }); - - QUnit.test('should support consuming the return value of `_.pairs`', function(assert) { - assert.expect(1); - - assert.deepEqual(_.zipObject(_.pairs(object)), object); - }); - - QUnit.test('should work in a lazy chain sequence', function(assert) { - assert.expect(1); - - if (!isNpm) { - var array = lodashStable.times(LARGE_ARRAY_SIZE, function(index) { - return ['key' + index, index]; - }); - - var actual = _(array).zipObject().map(square).filter(isEven).take().value(); - - assert.deepEqual(actual, _.take(_.filter(_.map(_.zipObject(array), square), isEven))); - } - else { - skipTest(assert); - } - }); - }()); - - /*--------------------------------------------------------------------------*/ - QUnit.module('lodash.zipWith'); (function() { @@ -22508,7 +22508,6 @@ 'invoke', 'keys', 'map', - 'pairs', 'pull', 'pullAll', 'pullAt', @@ -22523,6 +22522,7 @@ 'take', 'times', 'toArray', + 'toPairs', 'union', 'uniq', 'values', diff --git a/test/underscore.html b/test/underscore.html index e716d7632..c3074012b 100644 --- a/test/underscore.html +++ b/test/underscore.html @@ -343,11 +343,13 @@ 'mapObject': 'mapValues', 'matcher': 'matches', 'methods': 'functions', - 'object': 'zipObject', + 'object': 'fromPairs', + 'pairs': 'toPairs', 'pluck': 'map', 'restParam': 'restArgs', 'select': 'filter', - 'where': 'filter' + 'where': 'filter', + 'zipObject': 'fromPairs' }; var keyMap = {