sj-freitas/forofa

View on GitHub
lib/functions/README.md

Summary

Maintainability
Test Coverage
Below the many functions currently supported are documented.

## Table of Contents

- [concat](#concat)
- [count](#count)
- [every](#every)
- [filter](#filter)
- [first](#first)
- [get](#get)
- [join](#join)
- [last](#last)
- [map](#map)
- [mapMany](#mapmany)
- [reduce](#reduce)
- [repeat](#repeat)
- [single](#single)
- [skip](#skip)
- [slice](#slice)
- [some](#some)
- [take](#take)
- [toArray](#toarray)
- [toIterable](#toiterable)

## concat

Lazily concatenates two iterables by merging them together into a separate iteratable, it does not change any of the iterables.

### Example

```js
const { Iterable } = require("forofa");

const iterable1 = new Iterable([1, 2, 3, 4]);
const iterable2 = new Iterable("5678").map(t => parseInt(t));

for (const curr of iterable1.concat(iterable2)) {
  console.log(curr);
}
```

## count

Iterates the collection until its end and returns the amount of items.
**Warning**: This function can block your code in case of infinite iterables.

### Example

```js
const { Iterable } = require("forofa");

const iterable = new Iterable([1, 2, 3, 4]);

console.log(iterable.count());
```

This example will print `4`.

```js
const { Iterable } = require("forofa");

function* createInfiniteCollection() {
  let i = 0;
  while (true) {
    yield i;
  }
}

const iterable = new Iterable([1, 2, 3, 4]);

// This will cause a block!
iterable.count();
```

However, the operation can be concluded and return `Infinity` when it reaches the `INFINITY_THRESHOLD` parameter, which acts as a fail-safe. By default the threshold is set to `9007199254740992`, but it can be changed to a negative number so it'll never be reached.

## every

Similar to the [Array.prototype.every](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) function, gets whether or not all the elements contained in the iterable fulfil a certain criteria. For better performance, the iteration will stop once a value that does not fulfil the criteria is found.
**Warning**: This function can block your code in case of infinite iterables.

### Examples

```js
const { Iterable } = require("forofa");

const iterable1 = new Iterable([1, 2, 3, 4]);
const iterable2 = new Iterable([1, 2, -3, -4]);
const isPositiveNumber = curr => curr > 0;

console.log(iterable1.every(isPositiveNumber));
console.log(iterable2.every(isPositiveNumber));
```

This will print `true` and `false` in order.

To demonstrate that it doesn't go through all values, check the example below.

```js
const { Iterable } = require("forofa");

let iterationCount = 0;
function* addLogToArray(array) {
  for (const curr of array) {
    iterationCount++;
    yield curr;
  }
}

new Iterable(addLogToArray([1, 2, -3, 4, 5, 6])).every(curr => curr > 0);
console.log(iterationCount);
```

This will show `3`, as the iterator was iterated three times.

## filter

Similar to the [Array.prototype.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) function, but will function in a lazy manner, only filtering each item on demand. On every next call, it'll cycile through the iteratable until it finds an item that fulfils the condition.

### Example

```js
const { Iterable } = require("forofa");

const onlyEven = new Iterable([9, 2, 3, 40, 33, 35]).filter(
  curr => curr % 2 === 0
);

for (const curr of onlyEven) {
  console.log(curr);
}
```

This will print `2` and `40`.

## first

Will get the first element that fulfils the criteria and returns it. If no element is found it'll throw an error. This function was inspired on the [Linq First](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.first?redirectedfrom=MSDN&view=netframework-4.7.2#overloads).
**Warning**: If empty or there's no match, it'll throw an error.

### Example

```js
const { Iterable } = require("forofa");

const first = new Iterable([1, 2, -3, 4, 5, 6]).first(curr => curr < 0);
console.log(first);
```

It'll print `-3`.

## get

Given an index, it'll give the element at the specific position. It'll return undefined if reaches an out of bounds value.

### Example

```js
const { Iterable } = require("forofa");

function* infiniteSequence(startValue) {
  let i = startValue;
  for (;;) {
    yield i;
    i += 1;
  }
}

console.log(new Iterable(infiniteSequence(1)).get(5));
```

It'll print `6`.

## join

Similar to the [Array.prototype.join](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join), it's mostly an auxilary method. It'll convert the collection to a string and join the parts with the separator string.

### Example

```js
const { Iterable } = require("forofa");

function* daysOfTheWeek(startValue) {
  yield "Monday";
  yield "Tuesday";
  yield "Wednesday";
  yield "Thursday";
  yield "Friday";
  yield "Saturday";
  yield "Sunday";
}

const weekend = new Iterable(daysOfTheWeek())
  .skip(5)
  .take(2)
  .join(" and ");
console.log(weekend);
```

This will print `Saturday and Sunday`.

## last

Will get the last element that fulfils the criteria and returns it. If no element is found it'll throw an error. This function was inspired on the [Linq Last](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.last?view=netframework-4.7.2).
**Warning**: If empty or there's no match, it'll throw an error.
**Warning**: This function can block your code in case of infinite iterables.

### Examples

```js
const { Iterable } = require("forofa");

const last = new Iterable([1, 2, 3, 4, 5, 6]).last();
console.log(last);
```

It'll print `6`.
Check at this [RunKit](https://runkit.com/embed/t0acmy92rge3)

```js
const { Iterable } = require("forofa");

const last = new Iterable([1, 2, 3, 4, 5, 6]).last(t => t < 4);
console.log(last);
```

It'll print `3`.
Check at this [RunKit](https://runkit.com/embed/6ja0h8zgdh1y)

## map

Similar to the [Array.prototype.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) function, but will function in a lazy manner, only mapping each item on demand.

### Example

```js
const { Iterable } = require("forofa");

const numbersInText = ["1", "2", "3"];
const numbers = new Iterable(numbersInText).map(parseInt).map(t => t * 2);

for (const curr of numbers) {
  console.log(curr);
}
```

This will print `2`, `4` and `6`.

## mapMany

Takes inspiration on the [Linq SelectMany](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.selectmany?view=netframework-4.7.2) which takes a collection per individual item and flattens them as a single collection but in a lazy fashion. This function is very useful when having a collection of objects where each object has in itself another collection.

### Example

```js
const { Iterable } = require("forofa");

const customer1 = {
  products: ["Apples", "Bananas"]
};
const customer2 = {
  prodcuts: ["Oranges", "Melons"]
};

const fruits = new Iterable([customer1, customer2]).mapMany(t => t.products);

for (const fruit of fruits) {
  console.log(fruit);
}
```

This will print `Apples`, `Bananas`, `Oranges` and `Melons`.

## reduce

Similar to the [Array.prototype.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) function. Keeping the same behavior but working with all iterable types, not just arrays.

### Example

```js
const { Iterable } = require("forofa");

const sum = new Iterable("12345").reduce(
  (prev, next) => parseInt(prev) + parseInt(next)
);
console.log(sum);
```

This will print `15`.

## repeat

Creates a lazy collection of the same element repeated n times. It can be used to create infinite collections. It has O(1) creation cost as it doesn't necessarily create anything.

### Example

```js
const { repeat } = require("forofa/functions");

const words = repeat("word", 3);
for (const curr of words) {
  console.log(curr);
}
```

This will print `word` three times.

## single

Will get the single element that fulfils the criteria and returns it. If no element is found it'll throw an error. If there are more than 1 element from the criteria it'll throw an error. This function was inspired on the [Linq Single](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.single?view=netframework-4.7.2).
**Warning**: If empty or there's no match, it'll throw an error.
**Warning**: If more than 1 match, it'll throw an error.
**Warning**: If the collection is infinite and it has a predicate that is fulfilled just once, it can block your code.

### Examples

```js
const { Iterable } = require("forofa");

const single = new Iterable([1, 2, 3, 4, 5, 6]).single(t => t > 5);
console.log(single);
```

It'll print `6`.
Check at this [RunKit](https://runkit.com/embed/rx1ouvkjuqnp)

```js
const { Iterable } = require("forofa");

const single = new Iterable([1, 2, 3, 4, 5, 6]).single(t => t < 4);
console.log(single);
```

It'll throw an error.
Check at this [RunKit](https://runkit.com/embed/aprbtjg05p07)

## skip

Takes inspiration on the [Linq Skip](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.skip?view=netframework-4.7.2) which will pass through the n first elements.

### Example

```js
const { Iterable } = require("forofa");

const items = new Iterable([1, 2, 3, 4, 5]).skip(2);
for (const curr of items) {
  console.log(curr);
}
```

This will print `3`, `4` and `5`.

## slice

Similar to the [Array.prototype.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) function, but in a lazy fashion, it won't create a new collection or iterate through the items, it'll use the skip and take implementation under the hood.

### Example

```js
const { Iterable } = require("forofa");

const items = new Iterable([1, 2, 3, 4, 5]).slice(1, 4);
for (const curr of items) {
  console.log(curr);
}
```

This will print `2`, `3` and `4`.

## some

Similar to the [Array.prototype.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) function, gets whether or not all the elements contained in the iterable fulfil a certain criteria. For better performance, the iteration will stop once a value that does not fulfil the criteria is found.
**Warning**: This function can block your code in case of infinite iterables.

### Example

```js
const { Iterable } = require("forofa");

const iterable1 = new Iterable([1, 2, -3, -4]);
const iterable2 = new Iterable([1, 2, 3, 4]);
const isNegativeNumber = curr => curr < 0;

console.log(iterable1.some(isNegativeNumber));
console.log(iterable2.some(isNegativeNumber));
```

This will print `true` and `false` in order.

## take

Takes inspiration on the [Linq Take](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.take?view=netframework-4.7.2) which will take the n first elements.

### Example

```js
const { Iterable } = require("forofa");

const items = new Iterable([1, 2, 3, 4, 5]).take(3);
for (const curr of items) {
  console.log(curr);
}
```

This will print `1`, `2` and `3`.

## toArray

Concretizes the iterable to an array, materializing all its values.
**Warning**: This function can block your code in case of infinite iterables.

### Example

```js
const { Iterable } = require("forofa");

function* createCollection() {
  yield 1;
  yield 2;
  yield 3;
}

const items = new Iterable(createCollection()).toArray();
console.log(items);
```

This will print `Array(3) [1, 2, 3]`.

## toIterable

Wraps the single item as an iterable. This can be the equivalent to wrapping an item onto an array however this won't allocate an array in memory.

### Example

```js
const { toIterable } = require("forofa/functions");

// Equivalent to doing [5].
const item = toIterable(5);
for (const curr of item) {
  console.log(curr);
}
```

This will print `5`.