object_inverse_by.js (3891B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2018 The Stdlib Authors. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 /* eslint-disable callback-return */ 20 21 'use strict'; 22 23 // MODULES // 24 25 var objectKeys = require( './../../keys' ); 26 var isArray = require( '@stdlib/assert/is-array' ); 27 var isObject = require( '@stdlib/assert/is-plain-object' ); 28 var isObjectLike = require( '@stdlib/assert/is-object-like' ); 29 var isBoolean = require( '@stdlib/assert/is-boolean' ).isPrimitive; 30 var isFunction = require( '@stdlib/assert/is-function' ); 31 var hasOwnProp = require( '@stdlib/assert/has-own-property' ); 32 33 34 // MAIN // 35 36 /** 37 * Inverts an object, such that keys become values and values become keys, according to a transform function. 38 * 39 * @param {ObjectLike} obj - input object 40 * @param {Options} [opts] - function options 41 * @param {boolean} [opts.duplicates=true] - boolean indicating whether to store duplicate keys 42 * @param {Function} transform - transform function 43 * @throws {TypeError} first argument must be object-like 44 * @throws {TypeError} options argument must an an object 45 * @throws {TypeError} last argument must be a function 46 * @throws {TypeError} must provide valid options 47 * @returns {Object} inverted object 48 * 49 * @example 50 * function transform( key, value ) { 51 * return key + value; 52 * } 53 * var obj = { 54 * 'a': 'beep', 55 * 'b': 'boop' 56 * }; 57 * var out = invertBy( obj, transform ); 58 * // returns { 'abeep': 'a', 'bboop': 'b' } 59 * 60 * @example 61 * function transform( key, value ) { 62 * return value; 63 * } 64 * var obj = { 65 * 'a': 'beep', 66 * 'b': 'beep' 67 * }; 68 * var out = invertBy( obj, transform ); 69 * // returns { 'beep': [ 'a', 'b' ] } 70 * 71 * @example 72 * function transform( key, value ) { 73 * return value; 74 * } 75 * 76 * var obj = {}; 77 * obj.a = 'beep'; 78 * obj.b = 'boop'; 79 * obj.c = 'beep'; // inserted after `a` 80 * 81 * var opts = { 82 * 'duplicates': false 83 * }; 84 * var out = invertBy( obj, opts, transform ); 85 * // returns { 'beep': 'c', 'boop': 'b' } 86 */ 87 function invertBy( obj, opts, transform ) { 88 var allowDupes; 89 var keys; 90 var len; 91 var key; 92 var val; 93 var out; 94 var cb; 95 var v; 96 var i; 97 if ( !isObjectLike( obj ) ) { 98 throw new TypeError( 'invalid argument. First argument must be object-like. Value: `' + obj + '`.' ); 99 } 100 allowDupes = true; 101 if ( arguments.length === 2 ) { 102 cb = opts; 103 } else { 104 if ( !isObject( opts ) ) { 105 throw new TypeError( 'invalid argument. Options arguments must be an object. Value: `' + opts + '`.' ); 106 } 107 if ( hasOwnProp( opts, 'duplicates' ) ) { 108 allowDupes = opts.duplicates; 109 if ( !isBoolean( allowDupes ) ) { 110 throw new TypeError( 'invalid argument. `duplicates` option must be a boolean primitive. Option: `' + allowDupes + '`.' ); 111 } 112 } 113 cb = transform; 114 } 115 if ( !isFunction( cb ) ) { 116 throw new TypeError( 'invalid argument. Last argument must be a function. Value: `' + cb + '`.' ); 117 } 118 keys = objectKeys( obj ); 119 len = keys.length; 120 out = {}; 121 if ( allowDupes ) { 122 for ( i = 0; i < len; i++ ) { 123 key = keys[ i ]; 124 val = cb( key, obj[ key ], obj ); 125 if ( !hasOwnProp( out, val ) ) { 126 out[ val ] = key; 127 continue; 128 } 129 v = out[ val ]; 130 if ( isArray( v ) ) { 131 out[ val ].push( key ); 132 } else { 133 out[ val ] = [ v, key ]; 134 } 135 } 136 } else { 137 for ( i = 0; i < len; i++ ) { 138 key = keys[ i ]; 139 val = cb( key, obj[ key ], obj ); 140 out[ val ] = key; 141 } 142 } 143 return out; 144 } 145 146 147 // EXPORTS // 148 149 module.exports = invertBy;