time-to-botec

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

main.js (3429B)


      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 isArray = require( '@stdlib/assert/is-array' );
     24 
     25 
     26 // FUNCTIONS //
     27 
     28 /**
     29 * Recursively (and eagerly) attempts to resolve nested array dimensions.
     30 *
     31 * @private
     32 * @param {Array} shape - output array
     33 * @param {Array} arr - array
     34 * @returns {Array} shape array
     35 */
     36 function recurse( shape, arr ) {
     37 	var v = arr[ 0 ];
     38 	if ( isArray( v ) ) {
     39 		shape.push( v.length );
     40 		recurse( shape, v );
     41 	}
     42 	return shape;
     43 }
     44 
     45 /**
     46 * Recursively verifies that all nested arrays have consistent dimensions.
     47 *
     48 * @private
     49 * @param {PositiveInteger} ndims - number of dimensions
     50 * @param {Array} shape - shape array
     51 * @param {NonNegativeInteger} d - dimension
     52 * @param {Array} arr - array element to verify
     53 * @param {boolean} flg - boolean indicating whether to continue recursing
     54 * @returns {NonNegativeInteger} number of consistent dimensions
     55 */
     56 function check( ndims, shape, d, arr, flg ) {
     57 	var len;
     58 	var v;
     59 	var i;
     60 
     61 	// Get the size of the current dimension:
     62 	len = shape[ d ];
     63 
     64 	// Ensure that each array element is an array of the same size:
     65 	for ( i = 0; i < arr.length; i++ ) {
     66 		v = arr[ i ];
     67 
     68 		// If the array element is not an array or is not the same size, we have found an inconsistent dimension:
     69 		if ( !isArray( v ) || v.length !== len ) {
     70 			// `d` is one more than the index of the last consistent dimension and thus equal to the number of consistent dimensions:
     71 			return d;
     72 		}
     73 		// Recursively examine nested elements:
     74 		if ( flg ) {
     75 			v = check( ndims, shape, d+1, v, d+1 < ndims-1 );
     76 			if ( v < ndims ) {
     77 				// Propagate the number of consistent dimensions up the recursion chain...
     78 				return v;
     79 			}
     80 		}
     81 	}
     82 	return ndims;
     83 }
     84 
     85 
     86 // MAIN //
     87 
     88 /**
     89 * Determines (nested) array dimensions.
     90 *
     91 * @param {Array} arr - array
     92 * @throws {TypeError} must provide an array
     93 * @returns {Array} array shape
     94 *
     95 * @example
     96 * var arr = [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ];
     97 *
     98 * var shape = arrayShape( arr );
     99 * // returns [ 3, 3 ]
    100 *
    101 * @example
    102 * var arr = [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8 ] ];
    103 *
    104 * var shape = arrayShape( arr );
    105 * // returns [ 3 ]
    106 *
    107 * @example
    108 * var arr = [ [ 1, 2, 3 ], [ 4, 5, 6 ], null ];
    109 *
    110 * var shape = arrayShape( arr );
    111 * // returns [ 3 ]
    112 */
    113 function arrayShape( arr ) {
    114 	var shape;
    115 	var ndims;
    116 
    117 	if ( !isArray( arr ) ) {
    118 		throw new TypeError( 'invalid argument. Must provide an array. Value: `' + arr + '`.' );
    119 	}
    120 	// Initialize the shape/dimensions array:
    121 	shape = [ arr.length ];
    122 
    123 	// Eagerly determine array dimensions:
    124 	recurse( shape, arr );
    125 	ndims = shape.length;
    126 
    127 	// Check that all array element dimensions are consistent:
    128 	if ( ndims > 1 ) {
    129 		// If `check()` returns a value less than `ndims`, trim off the inconsistent dimensions:
    130 		shape.length = check( ndims, shape, 1, arr, ndims > 2 );
    131 	}
    132 	return shape;
    133 }
    134 
    135 
    136 // EXPORTS //
    137 
    138 module.exports = arrayShape;