1.0.1 • Published 4 years ago

ts-iterators v1.0.1

Weekly downloads
-
License
MIT
Repository
-
Last release
4 years ago

Test

ts-iterators

Ever been frustrated that you can't sort a Set, or get the first 10 elements in a Map? Well now you can! TS iterators offers a comprehensive collection of functions that operate on any Iterable values, and return Iterables in turn. This includes all the common JS Array methods; such as map, sort, reduce and slice! Some additional ones inspired by Rust, and a few new ones.

Why Iterators?

JS iterators are a very powerful. On a simple level they provide a standardised interface for accessing the element of any type of collections. At a more complex level iterators pull their values from their source, one element at a time. So they do not need to copy the entire contents of the collection. Even more clever is that the source doesn't need to be a collection, it could be a generator which creates a new value each time it pulled upon. This lazy nature means that if you only need to process part of a list, you only have to do the work for those values! Saving processing time and memory.

The hardest part of dealing with iterators in JS is that all the clever helpers for dealing with collections are methods on Arrays. While it's trivial to convert an iterator into an array you lose out on many of the advantages of using an iterator, making it is very wasteful. Hence the creation of this collection. Whereever possible everything is done without collecting up the entries of an iterator, and just works on an element by element basis. Outputs are also iterable values, allowing for easy composition, and of course everything is nicely typed to make it easy to use.

Example

Here is a simple example of composing a source (range), two operators (filter and map) and a consumer (join).

import { range, filter, map, join } from 'ts-iterators';

function isEven (value: number): boolean {
	return (v % 2) === 0;
}

let values: Iterable<number> = range(1, 10);
let even: Iterable<number> = filter(values, isEven);
let inverse: Iterable<string> = map(even, (v: number) => `${v} = ${1 / v}`)

console.log(join(inverse, '\n'))

Common gotcha

import { map } from 'ts-iterators'
map([1, 2, 3], console.log);

At first glance the above code looks perfectly correct. However, it doesn't log anything. Why is that? The answer is that map is an operator, not a consumer. Hence it does not consume it's source when used but rather creates a new source that can be consumed, which in turn consumes it's source. An easy way to consume an iterator is by using the spread operator like so.

import { map } from 'ts-iterators'
const incremented = map([1, 2, 3], v => v + 1);
console.log(...incremented); // 2, 3, 4

It's not uncommon to use Array.map to iterate over a map and then not use the new array it creates, mainly because it's more succinct than Array.forEach. But in the case of iterators the difference is a bit more stark, as the function isn't called unless you use the return value. You can just use forEach instead though:

import { forEach } from 'ts-iterators'
forEach([1, 2, 3], console.log);
// 1
// 2
// 3

Sources

A source creates a new iterable value based on a set of parameters.

  • range
  • entries
  • fromArray
  • fromIterator
  • infinity
  • keys
  • of
  • range
  • repeat

Operators

An operator takes 1 or more iterable values, performs an operation on them and emits 1 or more new iterable values containing the output.

  • buffer
  • chunk
  • concat
  • duplicate
  • fill
  • filter
  • flat
  • flatMap
  • map
  • reverse
  • skip
  • slice
  • sort
  • split
  • unzip
  • zip

Consumers

A consumer takes 1 or more iterable values, consumes their values and emits some form of output.

  • compare
  • every
  • find
  • findIndex
  • first
  • forEach
  • includes
  • indexOf
  • join
  • last
  • lastIndexOf
  • length
  • reduce
  • reduceRight
  • some