{"id":13599998,"url":"https://github.com/RobinMalfait/lazy-collections","last_synced_at":"2025-04-10T17:33:15.644Z","repository":{"id":42011622,"uuid":"239626029","full_name":"RobinMalfait/lazy-collections","owner":"RobinMalfait","description":"Collection of fast and lazy operations","archived":false,"fork":false,"pushed_at":"2023-10-19T06:23:23.000Z","size":680,"stargazers_count":400,"open_issues_count":2,"forks_count":23,"subscribers_count":8,"default_branch":"main","last_synced_at":"2024-04-24T17:41:58.306Z","etag":null,"topics":["functional-programming","javascript","lazy","lazy-collections"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RobinMalfait.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-02-10T22:23:17.000Z","updated_at":"2024-04-20T17:26:28.000Z","dependencies_parsed_at":"2023-02-06T15:46:19.096Z","dependency_job_id":"5d5fc0cd-291f-474e-9c52-7d7f04fbc9b1","html_url":"https://github.com/RobinMalfait/lazy-collections","commit_stats":{"total_commits":167,"total_committers":5,"mean_commits":33.4,"dds":0.07784431137724546,"last_synced_commit":"33f663ffabcab725dc0a79b9e7f1c0435fc4cd38"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobinMalfait%2Flazy-collections","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobinMalfait%2Flazy-collections/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobinMalfait%2Flazy-collections/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobinMalfait%2Flazy-collections/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RobinMalfait","download_url":"https://codeload.github.com/RobinMalfait/lazy-collections/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223442812,"owners_count":17145835,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["functional-programming","javascript","lazy","lazy-collections"],"created_at":"2024-08-01T17:01:24.191Z","updated_at":"2024-11-07T01:31:40.465Z","avatar_url":"https://github.com/RobinMalfait.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003ch3 align=\"center\"\u003e\n  Lazy Collections\n\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\n  Fast and lazy collection operations.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/RobinMalfait/lazy-collections/actions\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/RobinMalfait/lazy-collections/ci.yml?branch=main\u0026style=flat-square\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/lazy-collections\"\u003e\u003cimg src=\"https://img.shields.io/npm/dt/lazy-collections?style=flat-square\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/lazy-collections\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/lazy-collections?style=flat-square\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/lazy-collections\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/lazy-collections?style=flat-square\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/RobinMalfait/lazy-collections/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/npm/l/lazy-collections.svg?style=flat-square\" alt=\"License\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\nWorking with methods like `.map()`, `.filter()` and `.reduce()` is nice,\nhowever they create new arrays and everything is eagerly done before going to\nthe next step.\n\nThis is where lazy collections come in, under the hood we use [iterators][1] and\nasync iterators so that your data flows like a stream to have the optimal speed.\n\nAll functions should work with both `iterator` and `asyncIterator`, if one of\nthe functions uses an `asyncIterator` (for example when you introduce\n`delay(100)`), don't forget to `await` the result!\n\n[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterator_protocol\n\n```js\nlet program = pipe(\n  map((x) =\u003e x * 2),\n  filter((x) =\u003e x % 4 === 0),\n  filter((x) =\u003e x % 100 === 0),\n  filter((x) =\u003e x % 400 === 0),\n  toArray()\n)\n\nprogram(range(0, 1000000))\n```\n\n### Table of Contents\n\n- [Benchmark](#benchmark)\n- [API](#api)\n  - [Composing functions](#composing-functions)\n    - [`compose`](#compose)\n    - [`pipe`](#pipe)\n  - [Known array functions](#known-array-functions)\n    - [`at`](#at)\n    - [`concat`](#concat)\n    - [`every`](#every)\n    - [`filter`](#filter)\n    - [`find`](#find)\n    - [`findIndex`](#findindex)\n    - [`flatMap`](#flatMap)\n    - [`includes`](#includes)\n    - [`join`](#join)\n    - [`map`](#map)\n    - [`reduce`](#reduce)\n    - [`replace`](#replace)\n    - [`reverse`](#reverse)\n    - [`some`](#some)\n    - [`sort`](#sort)\n  - [Math / Statistics](#math--statistics)\n    - [`average`](#average)\n    - [`max`](#max)\n    - [`min`](#min)\n    - [`sum`](#sum)\n    - [`product`](#product)\n  - [Utilities](#utilities)\n    - [`batch`](#batch)\n    - [`chunk`](#chunk)\n    - [`compact`](#compact)\n    - [`delay`](#delay)\n    - [`flatten`](#flatten)\n    - [`generate`](#generate)\n    - [`groupBy`](#groupby)\n    - [`head`](#head)\n    - [`partition`](#partition)\n    - [`range`](#range)\n    - [`skip`](#skip)\n    - [`slice`](#slice)\n    - [`take`](#take)\n    - [`takeWhile`](#takewhile)\n    - [`tap`](#tap)\n    - [`toArray`](#toarray)\n    - [`toLength`](#tolength)\n    - [`toSet`](#toset)\n    - [`unique`](#unique)\n    - [`wait`](#wait)\n    - [`where`](#where)\n    - [`windows`](#windows)\n    - [`zip`](#zip)\n\n## Benchmark\n\n\u003e :warning: This is not a scientific benchmark, there are flaws with this. This\n\u003e is just meant to showcase the power of lazy-collections.\n\n|           \u0026nbsp; |   Lazy    |    Eager    | \u0026nbsp;            |\n| ---------------: | :-------: | :---------: | ----------------- |\n|         Duration | `2.19ms`  |   `1.29s`   | `589x` faster     |\n| Memory heapTotal | `9.48 MB` | `297.96 MB` | `31x` less memory |\n|  Memory heapUsed | `5.89 MB` | `265.46 MB` | `45x` less memory |\n\nMemory data collected using: http://nodejs.org/api/process.html#process_process_memoryusage\n\n```js\nimport { pipe, range, filter, takeWhile, slice, toArray } from 'lazy-collections'\n\n// Lazy example\nlet program = pipe(\n  range(0, 10_000_000),\n  filter((x) =\u003e x % 100 === 0),\n  filter((x) =\u003e x % 4 === 0),\n  filter((x) =\u003e x % 400 === 0),\n  takeWhile((x) =\u003e x \u003c 1_000),\n  slice(0, 1_000),\n  toArray()\n)\n\nprogram() // [ 0, 400, 800 ]\n```\n\n```js\n// Eager example\nfunction program() {\n  return (\n    // Equivalent of the range()\n    [...new Array(10_000_000).keys()]\n      .filter((x) =\u003e x % 100 === 0)\n      .filter((x) =\u003e x % 4 === 0)\n      .filter((x) =\u003e x % 400 === 0)\n\n      // Equivalent of the takeWhile\n      .reduce((acc, current) =\u003e {\n        return current \u003c 1_000 ? (acc.push(current), acc) : acc\n      }, [])\n      .slice(0, 1_000)\n  )\n}\n\nprogram() // [ 0, 400, 800 ]\n```\n\n---\n\nThis is actually a stupid non-real-world example. However, it is way more\nefficient at doing things. That said, _yes_ you can optimize the eager example\nway more if you want to. You can combine the `filter` / `reduce` / `...`. However,\nwhat I want to achieve is that we can have separated logic in different `filter`\nor `map` steps _without_ thinking about performance bottlenecks.\n\n## API\n\n### Composing functions\n\n#### `compose`\n\n[Table of contents](#table-of-contents)\n\nWe can use compose to compose functions together and return a new function which\ncombines all other functions.\n\n```js\nimport { compose } from 'lazy-collections'\n\n// Create a program (or a combination of functions)\nlet program = compose(fn1, fn2, fn3)\n\nprogram()\n// fn1(fn2(fn3()))\n```\n\n#### `pipe`\n\n[Table of contents](#table-of-contents)\n\nWe can use pipe to compose functions together and return a new function which\ncombines all other functions.\n\nThe difference between `pipe` and `compose` is the order of execution of the\nfunctions.\n\n```js\nimport { pipe } from 'lazy-collections'\n\n// Create a program (or a combination of functions)\nlet program = pipe(fn1, fn2, fn3)\n\nprogram()\n// fn3(fn2(fn1()))\n```\n\n### Known array functions\n\n#### `at`\n\n[Table of contents](#table-of-contents)\n\nReturns the value at the given index.\n\n```js\nimport { pipe, at } from 'lazy-collections'\n\nlet program = pipe(at(2))\n\nprogram([1, 2, 3, 4])\n\n// 3\n```\n\nYou can also pass a negative index to `at` to count back from the end of the array or iterator.\n\n\u003e **Warning**: Performance may be degraded because it has to exhaust the full iterator before it can count backwards!\n\n```js\nimport { pipe, at } from 'lazy-collections'\n\nlet program = pipe(at(-2))\n\nprogram([1, 2, 3, 4])\n\n// 3\n```\n\nIf a value can not be found at the given index, then `undefined` will be returned.\n\n```js\nimport { pipe, at } from 'lazy-collections'\n\nlet program = pipe(at(12))\n\nprogram([1, 2, 3, 4])\n\n// undefined\n```\n\n#### `concat`\n\n[Table of contents](#table-of-contents)\n\nConcat multiple iterators or arrays into a single iterator.\n\n```js\nimport { pipe, concat, toArray } from 'lazy-collections'\n\nlet program = pipe(concat([0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]), toArray())\n\nprogram()\n// [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]\n```\n\n#### `every`\n\n[Table of contents](#table-of-contents)\n\nShould return true if all values match the predicate.\n\n```js\nimport { pipe, every } from 'lazy-collections'\n\nlet program = pipe(every((x) =\u003e x === 2))\n\nprogram([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\n// false\n```\n\n#### `filter`\n\n[Table of contents](#table-of-contents)\n\nFilter out values that do not meet the condition.\n\n```js\nimport { pipe, filter, toArray } from 'lazy-collections'\n\nlet program = pipe(\n  filter((x) =\u003e x % 2 === 0),\n  toArray()\n)\n\nprogram([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\n// [ 2, 4, 6, 8, 10 ]\n```\n\n#### `find`\n\n[Table of contents](#table-of-contents)\n\nFind a value based on the given predicate.\n\n```js\nimport { pipe, find } from 'lazy-collections'\n\nlet program = pipe(find((x) =\u003e x === 2))\n\nprogram([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\n// 2\n```\n\n#### `findIndex`\n\n[Table of contents](#table-of-contents)\n\nFind an index based on the given predicate.\n\n```js\nimport { pipe, findIndex } from 'lazy-collections'\n\nlet program = pipe(findIndex((x) =\u003e x === 2))\n\nprogram([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\n// 1\n```\n\n#### `flatMap`\n\n[Table of contents](#table-of-contents)\n\nMap a value from A to B and flattens it afterwards.\n\n```js\nimport { pipe, flatMap, toArray } from 'lazy-collections'\n\nlet program = pipe(\n  flatMap((x) =\u003e [x * 2, x * 4]),\n  toArray()\n)\n\nprogram([1, 2, 3])\n// [ 2, 4, 4, 8, 6, 12 ]\n```\n\n#### `includes`\n\n[Table of contents](#table-of-contents)\n\nCheck if a value is included in an array or iterator.\n\n```js\nimport { pipe, includes } from 'lazy-collections'\n\nlet program = pipe(includes(1))\n\nprogram([1, 2, 3, 4])\n\n// true\n```\n\nEach value is compared using `Object.is`. This will guarantee that edge cases with `NaN` also work the same as `Array.prototype.includes`.\n\nOptionally, you can start searching from a positive index:\n\n```js\nimport { pipe, includes } from 'lazy-collections'\n\nlet program = pipe(includes(1, 1))\n\nprogram([1, 2, 3, 4])\n\n// false\n```\n\n#### `join`\n\n[Table of contents](#table-of-contents)\n\nJoin an array or iterator of strings.\n\n```js\nimport { pipe, join } from 'lazy-collections'\n\nlet program = pipe(join())\n\nprogram(['foo', 'bar', 'baz'])\n// 'foo,bar,baz'\n```\n\nOptionally, you can join with a separator string:\n\n```js\nimport { pipe, join } from 'lazy-collections'\n\nlet program = pipe(join(' '))\n\nprogram(['foo', 'bar', 'baz'])\n// 'foo bar baz'\n```\n\n#### `toLength`\n\n[Table of contents](#table-of-contents)\n\n\u003e **Warning**: Performance warning, it has to exhaust the full iterator before it can calculate length!\n\nGet the length of an array or iterator.\n\n```js\nimport { pipe, toLength, filter } from 'lazy-collections'\n\nlet program = pipe(\n  filter((x) =\u003e x % 2 === 0),\n  toLength()\n)\n\nprogram([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\n// 5\n```\n\n#### `map`\n\n[Table of contents](#table-of-contents)\n\nMap a value from A to B.\n\n```js\nimport { pipe, map, toArray } from 'lazy-collections'\n\nlet program = pipe(\n  map((x) =\u003e x * 2),\n  toArray()\n)\n\nprogram([1, 2, 3])\n// [ 2, 4, 6 ]\n```\n\n#### `reduce`\n\n[Table of contents](#table-of-contents)\n\nReduce the data to a single value.\n\n```js\nimport { pipe, reduce } from 'lazy-collections'\n\nlet program = pipe(reduce((total, current) =\u003e total + current, 0))\n\nprogram([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\n// 55\n```\n\n#### `replace`\n\n[Table of contents](#table-of-contents)\n\nReplace an item at a given index with a new value.\n\n```js\nimport { pipe, replace } from 'lazy-collections'\n\nlet program = pipe(replace(2, 42))\n\nprogram([1, 2, 3, 4])\n// [ 1, 2, 42, 4 ]\n```\n\n#### `reverse`\n\n\u003e **Warning**: Performance may be degraded because it has to exhaust the full iterator before it can reverse it!\n\n[Table of contents](#table-of-contents)\n\nReverses the iterator.\n\n```js\nimport { pipe, reverse, toArray } from 'lazy-collections'\n\nlet program = pipe(range(0, 5), reverse(), toArray())\n\nprogram()\n// [ 5, 4, 3, 2, 1, 0 ]\n```\n\n#### `some`\n\n[Table of contents](#table-of-contents)\n\nShould return true if some of the values match the predicate.\n\n```js\nimport { pipe, some } from 'lazy-collections'\n\nlet program = pipe(some((x) =\u003e x === 2))\n\nprogram([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\n// true\n```\n\n#### `sort`\n\n\u003e **Warning**: Performance may be degraded because it has to exhaust the full iterator before it can sort it!\n\n[Table of contents](#table-of-contents)\n\nShould sort the data. You can also provide a comparator function to the `sort` function.\n\n```js\nimport { pipe, generate, take, sort, toArray } from 'lazy-collections'\n\nlet program = pipe(\n  generate(() =\u003e (Math.random() * 100) | 0),\n  take(5),\n  sort(),\n  toArray()\n)\n\nprogram()\n// [ 11, 18, 24, 27, 83 ]\n```\n\n### Math / Statistics\n\n#### `average`\n\n[Table of contents](#table-of-contents)\n\n\u003e Alias: `mean`\n\nGets the average of number of values.\n\n```js\nimport { pipe, average, toArray } from 'lazy-collections'\n\nlet program = pipe(average())\n\nprogram([6, 7, 8, 9, 10])\n// 8\n```\n\n#### `max`\n\n[Table of contents](#table-of-contents)\n\nFind the maximum value of the given list\n\n```js\nimport { pipe, range, max } from 'lazy-collections'\n\nlet program = pipe(range(0, 5), max())\n\nprogram()\n// 5\n```\n\n#### `min`\n\n[Table of contents](#table-of-contents)\n\nFind the minimum value of the given list\n\n```js\nimport { pipe, range, min } from 'lazy-collections'\n\nlet program = pipe(range(5, 10), min())\n\nprogram()\n// 5\n```\n\n#### `sum`\n\n[Table of contents](#table-of-contents)\n\nShould sum an array or iterator.\n\n```js\nimport { pipe, sum } from 'lazy-collections'\n\nlet program = pipe(sum())\n\nprogram([1, 1, 2, 3, 2, 4, 5])\n// 18\n```\n\n#### `product`\n\n[Table of contents](#table-of-contents)\n\nShould multiply an array or iterator.\n\n```js\nimport { pipe, product } from 'lazy-collections'\n\nlet program = pipe(product())\n\nprogram([1, 1, 2, 3, 2, 4, 5])\n// 240\n```\n\n### Utilities\n\n#### `batch`\n\n[Table of contents](#table-of-contents)\n\nThis will call up to `N` amount of items in the stream immediately and wait for them in the correct\norder. If you have a list of API calls, then you can use this method to start calling the API in\nbatches of `N` instead of waiting for each API call sequentially.\n\n```js\nimport { pipe, range, map, batch, toArray } from 'lazy-collections'\n\nlet program = pipe(\n  range(0, 9),\n  map(() =\u003e fetch(`/users/${id}`)),\n  batch(5), // Will create 2 \"batches\" of 5 API calls\n  toArray()\n)\n\nawait program()\n// [ User1, User2, User3, User4, User5, User6, User7, User8, User9, User10 ];\n```\n\n#### `chunk`\n\n[Table of contents](#table-of-contents)\n\nChunk the data into pieces of a certain size.\n\n```js\nimport { pipe, chunk, toArray } from 'lazy-collections'\n\nlet program = pipe(chunk(3), toArray())\n\nprogram([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\n// [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ], [ 10 ] ];\n```\n\n#### `compact`\n\n[Table of contents](#table-of-contents)\n\nFilters out all falsey values.\n\n```js\nimport { pipe, compact, toArray } from 'lazy-collections'\n\nlet program = pipe(compact(), toArray())\n\nprogram([0, 1, true, false, null, undefined, '', 'test', NaN])\n// [ 1, true, 'test' ];\n```\n\n#### `delay`\n\n[Table of contents](#table-of-contents)\n\nWill make he whole program async. It will add a delay of x milliseconds when an\nitem goes through the stream.\n\n```js\nimport { pipe, range, delay, map, toArray } from 'lazy-collections'\n\nlet program = pipe(\n  range(0, 4),\n  delay(5000), // 5 seconds\n  map(() =\u003e new Date().toLocaleTimeString()),\n  toArray()\n)\n\nawait program()\n// [ '10:00:00', '10:00:05', '10:00:10', '10:00:15', '10:00:20' ];\n```\n\n#### `flatten`\n\n[Table of contents](#table-of-contents)\n\nBy default we will flatten recursively deep.\n\n```js\nimport { pipe, flatten, toArray } from 'lazy-collections'\n\nlet program = pipe(flatten(), toArray())\n\nprogram([1, 2, 3, [4, 5, 6, [7, 8], 9, 10]])\n// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]\n```\n\nBut you can also just flatten shallowly\n\n```js\nimport { pipe, flatten, toArray } from 'lazy-collections'\n\nlet program = pipe(flatten({ shallow: true }), toArray())\n\nprogram([1, 2, 3, [4, 5, 6, [7, 8], 9, 10]])\n// [ 1, 2, 3, 4, 5, 6, [ 7, 8 ], 9, 10 ]\n```\n\n#### `generate`\n\n[Table of contents](#table-of-contents)\n\nGenerate accepts a function that function will be called over and over again.\nDon't forget to combine this with a function that ensures that the data stream\nwill end. For example, you can use `take`, `takeWhile` or `slice`.\n\n```js\nimport { pipe, generate, take, toArray } from 'lazy-collections'\n\nlet program = pipe(generate(Math.random), take(3), toArray())\n\nprogram()\n// [ 0.7495421596380878, 0.09819118640607383, 0.2453718461872143 ]\n```\n\n#### `groupBy`\n\n[Table of contents](#table-of-contents)\n\nGroups the iterator to an object, using the keySelector function.\n\n```js\nimport { pipe, groupBy, range } from 'lazy-collections'\n\n// A function that will map the value to the nearest multitude. In this example\n// we will map values to the nearest multitude of 5. So that we can group by\n// this value.\nfunction snap(multitude: number, value: number) {\n  return Math.ceil(value / multitude) * multitude\n}\n\nlet program = pipe(\n  range(0, 10),\n  groupBy((x: number) =\u003e snap(5, x))\n)\n\nprogram()\n// {\n//   0: [0],\n//   5: [1, 2, 3, 4, 5],\n//   10: [6, 7, 8, 9, 10],\n// }\n```\n\n#### `head`\n\n[Table of contents](#table-of-contents)\n\n\u003e Alias: `first`\n\nGets the first value of the array / iterator. Returns `undefined` if there is no\nvalue.\n\n```js\nimport { pipe, chunk, toArray } from 'lazy-collections'\n\nlet program = pipe(head())\n\nprogram([6, 7, 8, 9, 10])\n// 6\n```\n\n#### `partition`\n\n[Table of contents](#table-of-contents)\n\nPartition data into 2 groups based on the predicate.\n\n```js\nimport { pipe, partition, range, toArray } from 'lazy-collections'\n\nlet program = pipe(\n  range(1, 4),\n  partition((x) =\u003e x % 2 !== 0),\n  toArray()\n)\n\nprogram()\n// [ [ 1, 3 ], [ 2, 4 ] ]\n```\n\n#### `range`\n\n[Table of contents](#table-of-contents)\n\nCreate a range of data using a lowerbound, upperbound and step. The step is\noptional and defaults to `1`.\n\n```js\nimport { pipe, range, toArray } from 'lazy-collections'\n\nlet program = pipe(range(5, 20, 5), toArray())\n\nprogram()\n// [ 5, 10, 15, 20 ]\n```\n\n#### `skip`\n\n[Table of contents](#table-of-contents)\n\nAllows you to skip X values of the input.\n\n```js\nimport { pipe, range, skip, toArray } from 'lazy-collections'\n\nlet program = pipe(range(0, 10), skip(3), toArray())\n\nprogram()\n// [ 3, 4, 5, 6, 7, 8, 9, 10 ]\n```\n\n#### `slice`\n\n[Table of contents](#table-of-contents)\n\nSlice a certain portion from your data set. It accepts a start index and an end\nindex.\n\n```js\nimport { pipe, range, slice, toArray } from 'lazy-collections'\n\nlet program = pipe(range(0, 10), slice(3, 5), toArray())\n\nprogram()\n// [ 3, 4, 5 ]\n\n// Without the slice this would have generated\n// [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]\n```\n\n#### `take`\n\n[Table of contents](#table-of-contents)\n\nAllows you to take X values of the input.\n\n```js\nimport { pipe, range, take, toArray } from 'lazy-collections'\n\nlet program = pipe(range(0, 10), take(3), toArray())\n\nprogram()\n// [ 0, 1, 2 ]\n```\n\n#### `takeWhile`\n\n[Table of contents](#table-of-contents)\n\nThis is similar to `take`, but instead of a number as a value it takes a\nfunction as a condition.\n\n```js\nimport { pipe, range, takeWhile, toArray } from 'lazy-collections'\n\nlet program = pipe(\n  range(0, 10),\n  takeWhile((x) =\u003e x \u003c 5),\n  toArray()\n)\n\nprogram()\n// [ 0, 1, 2, 3, 4 ]\n```\n\n#### `tap`\n\n[Table of contents](#table-of-contents)\n\nAllows you to tap into the stream, this way you can intercept each value.\n\n```js\nimport { pipe, range, tap, toArray } from 'lazy-collections'\n\nlet program = pipe(\n  range(0, 5),\n  tap((x) =\u003e {\n    console.log('x:', x)\n  }),\n  toArray()\n)\n\nprogram()\n// x: 0\n// x: 1\n// x: 2\n// x: 3\n// x: 4\n// x: 5\n// [ 0, 1, 2, 3, 4, 5 ]\n```\n\n#### `toArray`\n\n[Table of contents](#table-of-contents)\n\nConverts an array or an iterator to an actual array.\n\n```js\nimport { pipe, range, toArray } from 'lazy-collections'\n\nlet program = pipe(range(0, 10), toArray())\n\nprogram()\n// [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]\n```\n\n#### `toSet`\n\n[Table of contents](#table-of-contents)\n\nConverts an array or an iterator to Set.\n\n```js\nimport { pipe, range, toSet } from 'lazy-collections'\n\nlet program = pipe(range(0, 10), toSet())\n\nprogram()\n// Set (11) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }\n```\n\n#### `unique`\n\n[Table of contents](#table-of-contents)\n\nMake your data unique.\n\n```js\nimport { pipe, unique, toArray } from 'lazy-collections'\n\nlet program = pipe(unique(), toArray())\n\nprogram([1, 1, 2, 3, 2, 4, 5])\n// [ 1, 2, 3, 4, 5 ]\n```\n\n#### `wait`\n\n[Table of contents](#table-of-contents)\n\nWill make he whole program async. It is similar to delay, but there is no actual delay involved. If\nyour stream contains promises it will resolve those promises instead of possibly resolving to an\narray of pending promises.\n\n\u003e **Note**: This will execute the fetch calls sequentially, it will go to the next call once the\n\u003e first call is done. To prevent this you can use the [`batch`](#batch) function to help with this.\n\n```js\nimport { pipe, range, map, wait, toArray } from 'lazy-collections'\n\nlet program = pipe(\n  range(0, 4),\n  map((id) =\u003e fetch(`/my-api/users/${id}`)),\n  wait(),\n  toArray()\n)\n\nawait program()\n// [ User1, User2, User3, User4, User5 ];\n```\n\n#### `where`\n\n[Table of contents](#table-of-contents)\n\nFilter out values based on the given properties.\n\n```js\nimport { pipe, where, range, map, where, toArray } from 'lazy-collections'\n\nlet program = pipe(\n  range(15, 20),\n  map((age) =\u003e ({ age })),\n  where({ age: 18 }),\n  toArray()\n)\n\nprogram()\n// [ { age: 18 } ]\n```\n\n#### `windows`\n\n[Table of contents](#table-of-contents)\n\nGet a sliding window of a certain size, for the given input.\n\n```js\nimport { pipe, windows, toArray } from 'lazy-collections'\n\nlet program = pipe(windows(2), toArray())\n\nprogram(['l', 'a', 'z', 'y'])\n// [ [ 'l', 'a' ], [ 'a', 'z' ], [ 'z', 'y' ] ]\n```\n\n#### `zip`\n\n[Table of contents](#table-of-contents)\n\nZips multiple arrays / iterators together.\n\n```js\nimport { pipe, zip, toArray } from 'lazy-collections'\n\nlet program = pipe(zip(), toArray())\n\nprogram([\n  [0, 1, 2],\n  ['A', 'B', 'C'],\n])\n// [ [ 0, 'A' ], [ 1, 'B' ], [ 2, 'C' ] ]\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FRobinMalfait%2Flazy-collections","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FRobinMalfait%2Flazy-collections","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FRobinMalfait%2Flazy-collections/lists"}