object_inverse.js (3105B)
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 'use strict'; 20 21 // MODULES // 22 23 var objectKeys = require( './../../keys' ); 24 var isArray = require( '@stdlib/assert/is-array' ); 25 var isObject = require( '@stdlib/assert/is-plain-object' ); 26 var isObjectLike = require( '@stdlib/assert/is-object-like' ); 27 var isBoolean = require( '@stdlib/assert/is-boolean' ).isPrimitive; 28 var hasOwnProp = require( '@stdlib/assert/has-own-property' ); 29 30 31 // MAIN // 32 33 /** 34 * Inverts an object, such that keys become values and values become keys. 35 * 36 * @param {ObjectLike} obj - input object 37 * @param {Options} [opts] - function options 38 * @param {boolean} [opts.duplicates=true] - boolean indicating whether to store duplicate keys 39 * @throws {TypeError} first argument must be object-like 40 * @throws {TypeError} second argument must an an object 41 * @throws {TypeError} must provide valid options 42 * @returns {Object} inverted object 43 * 44 * @example 45 * var out = invert({ 46 * 'a': 'beep', 47 * 'b': 'boop' 48 * }); 49 * // returns { 'beep': 'a', 'boop': 'b' } 50 * 51 * @example 52 * var out = invert({ 53 * 'a': 'beep', 54 * 'b': 'beep' 55 * }); 56 * // returns { 'beep': [ 'a', 'b' ] } 57 * 58 * @example 59 * var obj = {}; 60 * obj.a = 'beep'; 61 * obj.b = 'boop'; 62 * obj.c = 'beep'; // inserted after `a` 63 * 64 * var out = invert( obj, { 65 * 'duplicates': false 66 * }); 67 * // returns { 'beep': 'c', 'boop': 'b' } 68 */ 69 function invert( obj, opts ) { 70 var allowDupes = true; 71 var keys; 72 var len; 73 var key; 74 var val; 75 var out; 76 var v; 77 var i; 78 if ( !isObjectLike( obj ) ) { 79 throw new TypeError( 'invalid argument. First argument must be object-like. Value: `' + obj + '`.' ); 80 } 81 if ( arguments.length > 1 ) { 82 if ( !isObject( opts ) ) { 83 throw new TypeError( 'invalid argument. Options arguments must be an object. Value: `' + opts + '`.' ); 84 } 85 if ( hasOwnProp( opts, 'duplicates' ) ) { 86 allowDupes = opts.duplicates; 87 if ( !isBoolean( allowDupes ) ) { 88 throw new TypeError( 'invalid argument. `duplicates` option must be a boolean primitive. Option: `' + allowDupes + '`.' ); 89 } 90 } 91 } 92 keys = objectKeys( obj ); 93 len = keys.length; 94 out = {}; 95 if ( allowDupes ) { 96 for ( i = 0; i < len; i++ ) { 97 key = keys[ i ]; 98 val = obj[ key ]; 99 if ( !hasOwnProp( out, val ) ) { 100 out[ val ] = key; 101 continue; 102 } 103 v = out[ val ]; 104 if ( isArray( v ) ) { 105 out[ val ].push( key ); 106 } else { 107 out[ val ] = [ v, key ]; 108 } 109 } 110 } else { 111 for ( i = 0; i < len; i++ ) { 112 key = keys[ i ]; 113 out[ obj[ key ] ] = key; 114 } 115 } 116 return out; 117 } 118 119 120 // EXPORTS // 121 122 module.exports = invert;