zip.js (4678B)
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 isBoolean = require( '@stdlib/assert/is-boolean' ).isPrimitive; 24 var isObject = require( '@stdlib/assert/is-plain-object' ); 25 var isArray = require( '@stdlib/assert/is-array' ); 26 var hasOwnProp = require( '@stdlib/assert/has-own-property' ); 27 28 29 // MAIN // 30 31 /** 32 * Generates array tuples from input arrays. 33 * 34 * @param {...Array} arr - input arrays to be zipped 35 * @param {Object} [opts] - function options 36 * @param {boolean} [opts.trunc=true] - boolean indicating whether to truncate arrays longer than the shortest input array 37 * @param {*} [opts.fill=null] - fill value used for arrays of unequal length 38 * @param {boolean} [opts.arrays=false] - boolean indicating whether an input array should be interpreted as an array of arrays to be zipped 39 * @throws {TypeError} must provide array arguments 40 * @throws {Error} must provide at least one array 41 * @throws {TypeError} options argument must be an object 42 * @throws {TypeError} must provide valid options 43 * @returns {Array} output array of arrays 44 * 45 * @example 46 * var zipped = zip( [ 1, 2 ], [ 'a', 'b' ] ); 47 * // returns [ [ 1, 'a' ], [ 2, 'b' ] ] 48 * 49 * @example 50 * var zipped = zip( [ 1, 2, 3 ], [ 'a', 'b' ] ); 51 * // returns [ [ 1, 'a' ], [ 2, 'b' ] ] 52 * 53 * @example 54 * var opts = { 55 * 'trunc': false 56 * }; 57 * 58 * var zipped = zip( [ 1, 2, 3 ], [ 'a', 'b' ], opts ); 59 * // returns [ [ 1, 'a' ], [ 2, 'b' ], [ 3, null ] ] 60 * 61 * @example 62 * var opts = { 63 * 'trunc': false, 64 * 'fill': '' 65 * }; 66 * 67 * var zipped = zip( [ 1, 2, 3 ], [ 'a', 'b' ], opts ); 68 * // returns [ [ 1, 'a' ], [ 2, 'b' ], [ 3, '' ] ] 69 * 70 * @example 71 * var arr = [ [ 1, 2 ], [ 'a', 'b' ] ]; 72 * 73 * // Default behavior: 74 * var zipped = zip( arr ); 75 * // returns [ [ [ 1, 2 ] ], [ [ 'a', 'b' ] ] ] 76 * 77 * // Array of arrays: 78 * zipped = zip( arr, { 'arrays': true } ); 79 * // returns [ [ 1, 'a' ], [ 2, 'b' ] ] 80 */ 81 function zip() { 82 var nargs; 83 var args; 84 var fill; 85 var opts; 86 var arg; 87 var flg; 88 var len; 89 var arr; 90 var out; 91 var val; 92 var i; 93 var j; 94 95 opts = {}; 96 fill = null; 97 args = Array.prototype.slice.call( arguments ); 98 nargs = args.length; 99 100 for ( i = 0; i < nargs-1; i++ ) { 101 if ( !isArray( args[i] ) ) { 102 throw new TypeError( 'invalid argument. Must provide array arguments. Value: `' + args[i] + '`.' ); 103 } 104 } 105 arg = args[ nargs-1 ]; 106 flg = isObject( arg ); 107 if ( !flg && !isArray( arg ) ) { 108 throw new TypeError( 'invalid argument. Last argument must be either an array or an options object. Value: `' + arg + '`.' ); 109 } 110 if ( flg ) { 111 opts = args.pop(); 112 } 113 nargs = args.length; 114 if ( nargs === 0 ) { 115 throw new Error( 'insufficient input arguments. Must provide at least one array.' ); 116 } 117 if ( hasOwnProp( opts, 'trunc' ) ) { 118 if ( !isBoolean( opts.trunc ) ) { 119 throw new TypeError( 'invalid option. `trunc` option must be a boolean. Value: `' + opts.trunc + '`.' ); 120 } 121 } else { 122 opts.trunc = true; 123 } 124 if ( hasOwnProp( opts, 'fill' ) ) { 125 fill = opts.fill; 126 } 127 if ( hasOwnProp( opts, 'arrays' ) ) { 128 if ( !isBoolean( opts.arrays ) ) { 129 throw new TypeError( 'invalid option. `arrays` option must be a boolean. Value: `' + opts.arrays + '`.' ); 130 } 131 } else { 132 opts.arrays = false; 133 } 134 if ( nargs === 1 && opts.arrays ) { 135 // Treat the lone array argument as an array of arrays to be zipped... 136 args = args[ 0 ]; 137 nargs = args.length; 138 } 139 len = args[ 0 ].length; 140 if ( opts.trunc ) { 141 // Find the min array length... 142 for ( i = 0; i < nargs; i++ ) { 143 val = args[ i ].length; 144 if ( val < len ) { 145 len = val; 146 } 147 } 148 } else { 149 // Find the max array length... 150 for ( i = 0; i < nargs; i++ ) { 151 val = args[ i ].length; 152 if ( val > len ) { 153 len = val; 154 } 155 } 156 } 157 out = new Array( len ); 158 for ( j = 0; j < len; j++ ) { 159 // Temporary array to store tuples... 160 arr = new Array( nargs ); 161 162 // Create the tuples... 163 for ( i = 0; i < nargs; i++ ) { 164 arg = args[ i ]; 165 166 // If an array is too short, use a fill value... 167 if ( arg.length <= j ) { 168 arr[ i ] = fill; 169 continue; 170 } 171 arr[ i ] = arg[ j ]; 172 } 173 out[ j ] = arr; 174 } 175 return out; 176 } 177 178 179 // EXPORTS // 180 181 module.exports = zip;