README.md (10752B)
1 <!-- 2 3 @license Apache-2.0 4 5 Copyright (c) 2018 The Stdlib Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 19 --> 20 21 # bifurcateByAsync 22 23 > Split values into two groups according to a predicate function. 24 25 <!-- Section to include introductory text. Make sure to keep an empty line after the intro `section` element and another before the `/section` close. --> 26 27 <section class="intro"> 28 29 </section> 30 31 <!-- /.intro --> 32 33 <!-- Package usage documentation. --> 34 35 <section class="usage"> 36 37 ## Usage 38 39 ```javascript 40 var bifurcateByAsync = require( '@stdlib/utils/async/bifurcate-by' ); 41 ``` 42 43 #### bifurcateByAsync( collection, \[options,] predicate, done ) 44 45 Splits values into two groups according to a `predicate` function, which specifies which group an element in the input `collection` belongs to. If a `predicate` function calls a provided callback with a truthy group value, a collection element belongs to the first group; otherwise, a collection element belongs to the second group. 46 47 ```javascript 48 function predicate( value, next ) { 49 setTimeout( onTimeout, value ); 50 function onTimeout() { 51 console.log( value ); 52 next( null, (value > 2000) ); 53 } 54 } 55 56 function done( error, result ) { 57 if ( error ) { 58 throw error; 59 } 60 console.log( result ); 61 } 62 63 var arr = [ 3000, 2500, 1000 ]; 64 65 bifurcateByAsync( arr, predicate, done ); 66 /* => 67 1000 68 2500 69 3000 70 [ [ 2500, 3000 ], [ 1000 ] ] 71 */ 72 ``` 73 74 The function accepts the following `options`: 75 76 - `limit`: the maximum number of pending invocations at any one time. Default: `infinity`. 77 - `series`: `boolean` indicating whether to sequentially invoke the `predicate` function for each `collection` element. If `true`, the function sets `options.limit=1`. Default: `false`. 78 - `returns`: specifies the output format. If the option equals `'values'`, the function returns group results as element values. If the option equals `'indices'`, the function returns group results as element indices. If the option equals `'*'`, the function returns group results as both element indices and values. Default: `'values'`. 79 - `thisArg`: the execution context for `predicate`. 80 81 By default, the function returns group results as element values. To return element indices, set the `returns` option to `'indices'`. 82 83 ```javascript 84 function predicate( value, next ) { 85 setTimeout( onTimeout, value ); 86 function onTimeout() { 87 console.log( value ); 88 next( null, (value > 2000) ); 89 } 90 } 91 92 function done( error, result ) { 93 if ( error ) { 94 throw error; 95 } 96 console.log( result ); 97 } 98 99 var arr = [ 3000, 2500, 1000 ]; 100 101 var opts = { 102 'returns': 'indices' 103 }; 104 bifurcateByAsync( arr, opts, predicate, done ); 105 /* => 106 1000 107 2500 108 3000 109 [ [ 1, 0 ], [ 2 ] ] 110 */ 111 ``` 112 113 To return index-value pairs, set the `returns` option to `'*'`. 114 115 ```javascript 116 function predicate( value, next ) { 117 setTimeout( onTimeout, value ); 118 function onTimeout() { 119 console.log( value ); 120 next( null, (value > 2000) ); 121 } 122 } 123 124 function done( error, result ) { 125 if ( error ) { 126 throw error; 127 } 128 console.log( result ); 129 } 130 131 var arr = [ 3000, 2500, 1000 ]; 132 133 var opts = { 134 'returns': '*' 135 }; 136 bifurcateByAsync( arr, opts, predicate, done ); 137 /* => 138 1000 139 2500 140 3000 141 [ [ [ 1, 2500 ], [ 0, 3000 ] ], [ [ 2, 1000 ] ] ] 142 */ 143 ``` 144 145 By default, all elements are processed concurrently, which means that the function does **not** guarantee completion order. To process each `collection` element sequentially, set the `series` option to `true`. 146 147 ```javascript 148 function predicate( value, next ) { 149 setTimeout( onTimeout, value ); 150 function onTimeout() { 151 console.log( value ); 152 next( null, (value > 2000) ); 153 } 154 } 155 156 function done( error, result ) { 157 if ( error ) { 158 throw error; 159 } 160 console.log( result ); 161 } 162 163 var arr = [ 3000, 2500, 1000 ]; 164 165 var opts = { 166 'series': true 167 }; 168 169 bifurcateByAsync( arr, opts, predicate, done ); 170 /* => 171 3000 172 2500 173 1000 174 [ [ 3000, 2500 ], [ 1000 ] ] 175 */ 176 ``` 177 178 To limit the maximum number of pending function invocations, set the `limit` option. 179 180 ```javascript 181 function predicate( value, next ) { 182 setTimeout( onTimeout, value ); 183 function onTimeout() { 184 console.log( value ); 185 next( null, (value > 2000) ); 186 } 187 } 188 189 function done( error, result ) { 190 if ( error ) { 191 throw error; 192 } 193 console.log( result ); 194 } 195 196 var arr = [ 3000, 2500, 1000 ]; 197 198 var opts = { 199 'limit': 2 200 }; 201 202 bifurcateByAsync( arr, opts, predicate, done ); 203 /* => 204 2500 205 3000 206 1000 207 [ [ 2500, 3000 ], [ 1000 ] ] 208 */ 209 ``` 210 211 To set the execution context of the `predicate` function, set the `thisArg` option. 212 213 ```javascript 214 function predicate( value, next ) { 215 this.count += 1; 216 setTimeout( onTimeout, value ); 217 function onTimeout() { 218 next( null, (value > 2000) ); 219 } 220 } 221 222 var arr = [ 3000, 2500, 1000 ]; 223 224 var context = { 225 'count': 0 226 }; 227 228 var opts = { 229 'thisArg': context 230 }; 231 232 bifurcateByAsync( arr, opts, predicate, done ); 233 234 function done( error, result ) { 235 if ( error ) { 236 throw error; 237 } 238 console.log( result ); 239 // => [ [ 2500, 3000 ], [ 1000 ] ] 240 241 console.log( context.count ); 242 // => 3 243 } 244 ``` 245 246 When invoked, the `predicate` function is provided a maximum of four arguments: 247 248 - `value`: collection value. 249 - `index`: collection index. 250 - `collection`: the input `collection`. 251 - `next`: a callback which should be called once the `predicate` function has finished processing a collection `value`. 252 253 The actual number of provided arguments depends on function `length`. If the `predicate` function accepts two arguments, the `predicate` function is provided `value` and `next`. If the `predicate` function accepts three arguments, the `predicate` function is provided `value`, `index`, and `next`. For every other `predicate` function signature, the `predicate` function is provided all four arguments. 254 255 ```javascript 256 function predicate( value, i, collection, next ) { 257 console.log( 'collection: %s. %d: %d', collection.join( ',' ), i, value ); 258 setTimeout( onTimeout, value ); 259 function onTimeout() { 260 console.log( value ); 261 next( null, (value > 2000) ); 262 } 263 } 264 265 function done( error, result ) { 266 if ( error ) { 267 throw error; 268 } 269 console.log( result ); 270 } 271 272 var arr = [ 3000, 2500, 1000 ]; 273 274 bifurcateByAsync( arr, predicate, done ); 275 /* => 276 collection: 3000,2500,1000. 0: 3000 277 collection: 3000,2500,1000. 1: 2500 278 collection: 3000,2500,1000. 2: 1000 279 1000 280 2500 281 3000 282 [ [ 2500, 3000 ], [ 1000 ] ] 283 */ 284 ``` 285 286 #### bifurcateByAsync.factory( \[options,] predicate ) 287 288 Returns a `function` which invokes a `predicate` function once for each element in a `collection`. 289 290 ```javascript 291 function predicate( value, next ) { 292 setTimeout( onTimeout, value ); 293 function onTimeout() { 294 console.log( value ); 295 next( null, (value > 2000) ); 296 } 297 } 298 299 function done( error, result ) { 300 if ( error ) { 301 throw error; 302 } 303 console.log( result ); 304 } 305 306 var f = bifurcateByAsync.factory( predicate ); 307 308 var arr1 = [ 3000, 2500, 1000 ]; 309 310 f( arr1, done ); 311 /* => 312 1000 313 2500 314 3000 315 [ [ 2500, 3000 ], [ 1000 ] ] 316 */ 317 318 var arr2 = [ 300, 250, 100 ]; 319 320 f( arr2, done ); 321 /* => 322 100 323 250 324 300 325 [ [], [ 100, 250, 300 ] ] 326 */ 327 ``` 328 329 The function accepts the same `options` as `bifurcateByAsync()`. 330 331 </section> 332 333 <!-- /.usage --> 334 335 <!-- Package usage notes. Make sure to keep an empty line after the `section` element and another before the `/section` close. --> 336 337 <section class="notes"> 338 339 ## Notes 340 341 - A `collection` may be either an [`Array`][mdn-array], [`Typed Array`][mdn-typed-array], or an array-like [`Object`][mdn-object] (excluding `strings` and `functions`). 342 - If a provided function calls the `next` callback with a truthy `error` argument, the function suspends execution and immediately calls the `done` callback for subsequent `error` handling. 343 - The function does **not** support dynamic `collection` resizing. 344 - The function does **not** skip `undefined` elements. 345 - If provided an empty `collection`, the function calls the `done` callback with an empty `array` for the group results. 346 - **Neither** `bifurcateByAsync` nor the function returned by the `factory` method **guarantee** asynchronous execution. To guarantee asynchrony, wrap the `done` callback in a function which either executes at the end of the current stack (e.g., `nextTick`) or during a subsequent turn of the event loop (e.g., `setImmediate`, `setTimeout`). 347 348 </section> 349 350 <!-- /.notes --> 351 352 <!-- Package usage examples. --> 353 354 <section class="examples"> 355 356 ## Examples 357 358 <!-- eslint no-undef: "error" --> 359 360 ```javascript 361 var resolve = require( 'path' ).resolve; 362 var readFile = require( '@stdlib/fs/read-file' ); 363 var bifurcateByAsync = require( '@stdlib/utils/async/bifurcate-by' ); 364 365 var files = [ 366 resolve( __dirname, 'package.json' ), 367 resolve( __dirname, 'README.md' ), 368 resolve( __dirname, 'beep.boop.md' ) 369 ]; 370 371 function done( error, result ) { 372 if ( error ) { 373 throw error; 374 } 375 console.log( result ); 376 } 377 378 function predicate( file, next ) { 379 var opts = { 380 'encoding': 'utf8' 381 }; 382 readFile( file, opts, onFile ); 383 384 function onFile( error ) { 385 if ( error ) { 386 return next( null, false ); 387 } 388 next( null, true ); 389 } 390 } 391 392 bifurcateByAsync( files, predicate, done ); 393 ``` 394 395 </section> 396 397 <!-- /.examples --> 398 399 <!-- Section to include cited references. If references are included, add a horizontal rule *before* the section. Make sure to keep an empty line after the `section` element and another before the `/section` close. --> 400 401 <section class="references"> 402 403 </section> 404 405 <!-- /.references --> 406 407 <!-- Section for all links. Make sure to keep an empty line after the `section` element and another before the `/section` close. --> 408 409 <section class="links"> 410 411 [mdn-array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array 412 413 [mdn-typed-array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray 414 415 [mdn-object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object 416 417 </section> 418 419 <!-- /.links -->