time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

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;