time-to-botec

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

README.md (11455B)


      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 # groupByAsync
     22 
     23 > Group values according to an indicator 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 groupByAsync = require( '@stdlib/utils/async/group-by' );
     41 ```
     42 
     43 #### groupByAsync( collection, \[options,] indicator, done )
     44 
     45 Groups values according to an `indicator` function, which specifies which group an element in the input `collection` belongs to.
     46 
     47 ```javascript
     48 function indicator( 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 groupByAsync( arr, indicator, done );
     66 /* =>
     67     1000
     68     2500
     69     3000
     70     { 'true': [ 2500, 3000 ], 'false': [ 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 `indicator` 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 `indicator`.
     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 indicator( 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 groupByAsync( arr, opts, indicator, done );
    105 /* =>
    106     1000
    107     2500
    108     3000
    109     { 'true': [ 1, 0 ], 'false': [ 2 ] }
    110 */
    111 ```
    112 
    113 To return index-value pairs, set the `returns` option to `'*'`.
    114 
    115 ```javascript
    116 function indicator( 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 groupByAsync( arr, opts, indicator, done );
    137 /* =>
    138     1000
    139     2500
    140     3000
    141     { 'true': [ [ 1, 2500 ], [ 0, 3000 ] ], 'false': [ [ 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 indicator( 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 groupByAsync( arr, opts, indicator, done );
    170 /* =>
    171     3000
    172     2500
    173     1000
    174     { 'true': [ 3000, 2500 ], 'false': [ 1000 ] }
    175 */
    176 ```
    177 
    178 To limit the maximum number of pending function invocations, set the `limit` option.
    179 
    180 ```javascript
    181 function indicator( 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 groupByAsync( arr, opts, indicator, done );
    203 /* =>
    204     2500
    205     3000
    206     1000
    207     { 'true': [ 2500, 3000 ], 'false': [ 1000 ] }
    208 */
    209 ```
    210 
    211 To set the execution context of the `indicator` function, set the `thisArg` option.
    212 
    213 ```javascript
    214 function indicator( 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 groupByAsync( arr, opts, indicator, done );
    233 
    234 function done( error, result ) {
    235     if ( error ) {
    236         throw error;
    237     }
    238     console.log( result );
    239     // => { 'true': [ 2500, 3000 ], 'false': [ 1000 ] }
    240 
    241     console.log( context.count );
    242     // => 3
    243 }
    244 ```
    245 
    246 When invoked, the `indicator` 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 `indicator` function has finished processing a collection `value`.
    252 
    253 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.
    254 
    255 ```javascript
    256 function indicator( 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 groupByAsync( arr, indicator, 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     { 'true': [ 2500, 3000 ], 'false': [ 1000 ] }
    283 */
    284 ```
    285 
    286 #### groupByAsync.factory( \[options,] indicator )
    287 
    288 Returns a `function` which invokes an `indicator` function once for each element in a `collection`.
    289 
    290 ```javascript
    291 function indicator( 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 = groupByAsync.factory( indicator );
    307 
    308 var arr1 = [ 3000, 2500, 1000 ];
    309 
    310 f( arr1, done );
    311 /* =>
    312     1000
    313     2500
    314     3000
    315     { 'true': [ 2500, 3000 ], 'false': [ 1000 ] }
    316 */
    317 
    318 var arr2 = [ 300, 250, 100 ];
    319 
    320 f( arr2, done );
    321 /* =>
    322     100
    323     250
    324     300
    325     { 'false': [ 100, 250, 300 ] }
    326 */
    327 ```
    328 
    329 The function accepts the same `options` as `groupByAsync()`.
    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 
    343 -   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.
    344 
    345 -   The function does **not** support dynamic `collection` resizing.
    346 
    347 -   The function does **not** skip `undefined` elements.
    348 
    349 -   If provided an empty `collection`, the function calls the `done` callback with an empty `object` for the group results.
    350 
    351 -   **Neither** `groupByAsync` 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`).
    352 
    353 -   The `group` returned by an `indicator` function should be a value which can be serialized as an `object` key. As a counterexample,
    354 
    355     ```javascript
    356     function indicator( value, next ) {
    357         setTimeout( onTimeout, value );
    358         function onTimeout() {
    359             console.log( value );
    360             next( null, {} );
    361         }
    362     }
    363 
    364     function done( error, result ) {
    365         if ( error ) {
    366             throw error;
    367         }
    368         console.log( result );
    369     }
    370 
    371     var arr = [ 3000, 2500, 1000 ];
    372 
    373     groupByAsync( arr, indicator, done );
    374     /* =>
    375         1000
    376         2500
    377         3000
    378         { '[object Object]': [ 1000, 2500, 3000 ] }
    379     */
    380     ```
    381 
    382     while each group identifier is unique, all collection elements resolve to the same group because each group identifier serializes to the same `string`.
    383 
    384 </section>
    385 
    386 <!-- /.notes -->
    387 
    388 <!-- Package usage examples. -->
    389 
    390 <section class="examples">
    391 
    392 ## Examples
    393 
    394 <!-- eslint no-undef: "error" -->
    395 
    396 ```javascript
    397 var resolve = require( 'path' ).resolve;
    398 var readFile = require( '@stdlib/fs/read-file' );
    399 var groupByAsync = require( '@stdlib/utils/async/group-by' );
    400 
    401 var files = [
    402     resolve( __dirname, 'package.json' ),
    403     resolve( __dirname, 'README.md' ),
    404     resolve( __dirname, 'beep.boop.md' )
    405 ];
    406 
    407 function done( error, result ) {
    408     if ( error ) {
    409         throw error;
    410     }
    411     console.log( result );
    412 }
    413 
    414 function indicator( file, next ) {
    415     var opts = {
    416         'encoding': 'utf8'
    417     };
    418     readFile( file, opts, onFile );
    419 
    420     function onFile( error ) {
    421         if ( error ) {
    422             return next( null, 'nonreadable' );
    423         }
    424         next( null, 'readable' );
    425     }
    426 }
    427 
    428 groupByAsync( files, indicator, done );
    429 ```
    430 
    431 </section>
    432 
    433 <!-- /.examples -->
    434 
    435 <!-- 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. -->
    436 
    437 <section class="references">
    438 
    439 </section>
    440 
    441 <!-- /.references -->
    442 
    443 <!-- Section for all links. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
    444 
    445 <section class="links">
    446 
    447 [mdn-array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
    448 
    449 [mdn-typed-array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray
    450 
    451 [mdn-object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
    452 
    453 </section>
    454 
    455 <!-- /.links -->