|
||
---|---|---|
.. | ||
docs | ||
lib | ||
package.json | ||
README.md |
groupByAsync
Group values according to an indicator function.
Usage
var groupByAsync = require( '@stdlib/utils/async/group-by' );
groupByAsync( collection, [options,] indicator, done )
Groups values according to an indicator
function, which specifies which group an element in the input collection
belongs to.
function indicator( 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 ];
groupByAsync( arr, indicator, done );
/* =>
1000
2500
3000
{ 'true': [ 2500, 3000 ], 'false': [ 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 theindicator
function for eachcollection
element. Iftrue
, the function setsoptions.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 forindicator
.
By default, the function returns group results as element values. To return element indices, set the returns
option to 'indices'
.
function indicator( 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'
};
groupByAsync( arr, opts, indicator, done );
/* =>
1000
2500
3000
{ 'true': [ 1, 0 ], 'false': [ 2 ] }
*/
To return index-value pairs, set the returns
option to '*'
.
function indicator( 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': '*'
};
groupByAsync( arr, opts, indicator, done );
/* =>
1000
2500
3000
{ 'true': [ [ 1, 2500 ], [ 0, 3000 ] ], 'false': [ [ 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
.
function indicator( 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
};
groupByAsync( arr, opts, indicator, done );
/* =>
3000
2500
1000
{ 'true': [ 3000, 2500 ], 'false': [ 1000 ] }
*/
To limit the maximum number of pending function invocations, set the limit
option.
function indicator( 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
};
groupByAsync( arr, opts, indicator, done );
/* =>
2500
3000
1000
{ 'true': [ 2500, 3000 ], 'false': [ 1000 ] }
*/
To set the execution context of the indicator
function, set the thisArg
option.
function indicator( 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
};
groupByAsync( arr, opts, indicator, done );
function done( error, result ) {
if ( error ) {
throw error;
}
console.log( result );
// => { 'true': [ 2500, 3000 ], 'false': [ 1000 ] }
console.log( context.count );
// => 3
}
When invoked, the indicator
function is provided a maximum of four arguments:
value
: collection value.index
: collection index.collection
: the inputcollection
.next
: a callback which should be called once theindicator
function has finished processing a collectionvalue
.
The actual number of provided arguments depends on function length
. If the indicator
function accepts two arguments, the indicator
function is provided value
and next
. If the indicator
function accepts three arguments, the indicator
function is provided value
, index
, and next
. For every other indicator
function signature, the indicator
function is provided all four arguments.
function indicator( 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 ];
groupByAsync( arr, indicator, done );
/* =>
collection: 3000,2500,1000. 0: 3000
collection: 3000,2500,1000. 1: 2500
collection: 3000,2500,1000. 2: 1000
1000
2500
3000
{ 'true': [ 2500, 3000 ], 'false': [ 1000 ] }
*/
groupByAsync.factory( [options,] indicator )
Returns a function
which invokes an indicator
function once for each element in a collection
.
function indicator( 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 = groupByAsync.factory( indicator );
var arr1 = [ 3000, 2500, 1000 ];
f( arr1, done );
/* =>
1000
2500
3000
{ 'true': [ 2500, 3000 ], 'false': [ 1000 ] }
*/
var arr2 = [ 300, 250, 100 ];
f( arr2, done );
/* =>
100
250
300
{ 'false': [ 100, 250, 300 ] }
*/
The function accepts the same options
as groupByAsync()
.
Notes
-
A
collection
may be either anArray
,Typed Array
, or an array-likeObject
(excludingstrings
andfunctions
). -
If a provided function calls the
next
callback with a truthyerror
argument, the function suspends execution and immediately calls thedone
callback for subsequenterror
handling. -
The function does not support dynamic
collection
resizing. -
The function does not skip
undefined
elements. -
If provided an empty
collection
, the function calls thedone
callback with an emptyobject
for the group results. -
Neither
groupByAsync
nor the function returned by thefactory
method guarantee asynchronous execution. To guarantee asynchrony, wrap thedone
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
). -
The
group
returned by anindicator
function should be a value which can be serialized as anobject
key. As a counterexample,function indicator( value, next ) { setTimeout( onTimeout, value ); function onTimeout() { console.log( value ); next( null, {} ); } } function done( error, result ) { if ( error ) { throw error; } console.log( result ); } var arr = [ 3000, 2500, 1000 ]; groupByAsync( arr, indicator, done ); /* => 1000 2500 3000 { '[object Object]': [ 1000, 2500, 3000 ] } */
while each group identifier is unique, all collection elements resolve to the same group because each group identifier serializes to the same
string
.
Examples
var resolve = require( 'path' ).resolve;
var readFile = require( '@stdlib/fs/read-file' );
var groupByAsync = require( '@stdlib/utils/async/group-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 indicator( file, next ) {
var opts = {
'encoding': 'utf8'
};
readFile( file, opts, onFile );
function onFile( error ) {
if ( error ) {
return next( null, 'nonreadable' );
}
next( null, 'readable' );
}
}
groupByAsync( files, indicator, done );