# bifurcateByAsync > Split values into two groups according to a predicate function.
## Usage ```javascript var bifurcateByAsync = require( '@stdlib/utils/async/bifurcate-by' ); ``` #### bifurcateByAsync( collection, \[options,] predicate, done ) 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. ```javascript function predicate( value, next ) { setTimeout( onTimeout, value ); function onTimeout() { console.log( value ); next( null, (value > 2000) ); } } function done( error, result ) { if ( error ) { throw error; } console.log( result ); } var arr = [ 3000, 2500, 1000 ]; bifurcateByAsync( arr, predicate, done ); /* => 1000 2500 3000 [ [ 2500, 3000 ], [ 1000 ] ] */ ``` The function accepts the following `options`: - `limit`: the maximum number of pending invocations at any one time. Default: `infinity`. - `series`: `boolean` indicating whether to sequentially invoke the `predicate` function for each `collection` element. If `true`, the function sets `options.limit=1`. Default: `false`. - `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'`. - `thisArg`: the execution context for `predicate`. By default, the function returns group results as element values. To return element indices, set the `returns` option to `'indices'`. ```javascript function predicate( value, next ) { setTimeout( onTimeout, value ); function onTimeout() { console.log( value ); next( null, (value > 2000) ); } } function done( error, result ) { if ( error ) { throw error; } console.log( result ); } var arr = [ 3000, 2500, 1000 ]; var opts = { 'returns': 'indices' }; bifurcateByAsync( arr, opts, predicate, done ); /* => 1000 2500 3000 [ [ 1, 0 ], [ 2 ] ] */ ``` To return index-value pairs, set the `returns` option to `'*'`. ```javascript function predicate( value, next ) { setTimeout( onTimeout, value ); function onTimeout() { console.log( value ); next( null, (value > 2000) ); } } function done( error, result ) { if ( error ) { throw error; } console.log( result ); } var arr = [ 3000, 2500, 1000 ]; var opts = { 'returns': '*' }; bifurcateByAsync( arr, opts, predicate, done ); /* => 1000 2500 3000 [ [ [ 1, 2500 ], [ 0, 3000 ] ], [ [ 2, 1000 ] ] ] */ ``` 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`. ```javascript function predicate( value, next ) { setTimeout( onTimeout, value ); function onTimeout() { console.log( value ); next( null, (value > 2000) ); } } function done( error, result ) { if ( error ) { throw error; } console.log( result ); } var arr = [ 3000, 2500, 1000 ]; var opts = { 'series': true }; bifurcateByAsync( arr, opts, predicate, done ); /* => 3000 2500 1000 [ [ 3000, 2500 ], [ 1000 ] ] */ ``` To limit the maximum number of pending function invocations, set the `limit` option. ```javascript function predicate( value, next ) { setTimeout( onTimeout, value ); function onTimeout() { console.log( value ); next( null, (value > 2000) ); } } function done( error, result ) { if ( error ) { throw error; } console.log( result ); } var arr = [ 3000, 2500, 1000 ]; var opts = { 'limit': 2 }; bifurcateByAsync( arr, opts, predicate, done ); /* => 2500 3000 1000 [ [ 2500, 3000 ], [ 1000 ] ] */ ``` To set the execution context of the `predicate` function, set the `thisArg` option. ```javascript function predicate( value, next ) { this.count += 1; setTimeout( onTimeout, value ); function onTimeout() { next( null, (value > 2000) ); } } var arr = [ 3000, 2500, 1000 ]; var context = { 'count': 0 }; var opts = { 'thisArg': context }; bifurcateByAsync( arr, opts, predicate, done ); function done( error, result ) { if ( error ) { throw error; } console.log( result ); // => [ [ 2500, 3000 ], [ 1000 ] ] console.log( context.count ); // => 3 } ``` When invoked, the `predicate` function is provided a maximum of four arguments: - `value`: collection value. - `index`: collection index. - `collection`: the input `collection`. - `next`: a callback which should be called once the `predicate` function has finished processing a collection `value`. 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. ```javascript function predicate( value, i, collection, next ) { console.log( 'collection: %s. %d: %d', collection.join( ',' ), i, value ); setTimeout( onTimeout, value ); function onTimeout() { console.log( value ); next( null, (value > 2000) ); } } function done( error, result ) { if ( error ) { throw error; } console.log( result ); } var arr = [ 3000, 2500, 1000 ]; bifurcateByAsync( arr, predicate, done ); /* => collection: 3000,2500,1000. 0: 3000 collection: 3000,2500,1000. 1: 2500 collection: 3000,2500,1000. 2: 1000 1000 2500 3000 [ [ 2500, 3000 ], [ 1000 ] ] */ ``` #### bifurcateByAsync.factory( \[options,] predicate ) Returns a `function` which invokes a `predicate` function once for each element in a `collection`. ```javascript function predicate( value, next ) { setTimeout( onTimeout, value ); function onTimeout() { console.log( value ); next( null, (value > 2000) ); } } function done( error, result ) { if ( error ) { throw error; } console.log( result ); } var f = bifurcateByAsync.factory( predicate ); var arr1 = [ 3000, 2500, 1000 ]; f( arr1, done ); /* => 1000 2500 3000 [ [ 2500, 3000 ], [ 1000 ] ] */ var arr2 = [ 300, 250, 100 ]; f( arr2, done ); /* => 100 250 300 [ [], [ 100, 250, 300 ] ] */ ``` The function accepts the same `options` as `bifurcateByAsync()`.
## Notes - 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`). - 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. - The function does **not** support dynamic `collection` resizing. - The function does **not** skip `undefined` elements. - If provided an empty `collection`, the function calls the `done` callback with an empty `array` for the group results. - **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`).
## Examples ```javascript var resolve = require( 'path' ).resolve; var readFile = require( '@stdlib/fs/read-file' ); var bifurcateByAsync = require( '@stdlib/utils/async/bifurcate-by' ); var files = [ resolve( __dirname, 'package.json' ), resolve( __dirname, 'README.md' ), resolve( __dirname, 'beep.boop.md' ) ]; function done( error, result ) { if ( error ) { throw error; } console.log( result ); } function predicate( file, next ) { var opts = { 'encoding': 'utf8' }; readFile( file, opts, onFile ); function onFile( error ) { if ( error ) { return next( null, false ); } next( null, true ); } } bifurcateByAsync( files, predicate, done ); ```