extra-iterator
v0.15.2
Published
An extension of the Iterator class with additional utility helper functions.
Downloads
177
Maintainers
Readme
extra-iterator
An extension of JavaScript's built-in Iterator class, with several utility functions for transforming and aggregating sequences of values.
Contributions are welcome. 🤗
Features
- 30+ utility methods
- Lazy operations
- Zero dependencies 🎉
- Fully typed with TypeScript
- 100% test coverage
Installation
npm install extra-iteratorRuntime requirements
This package extends the built-in Iterator class and uses the Iterator Helpers API.
Use it in a runtime that already supports iterator helpers, or load an appropriate polyfill.
Usage Examples
Work with ranges
import { ExtraIterator } from 'extra-iterator';
const range = ExtraIterator.range(1, 6)
.map(n => n * 2)
.toArray();
console.log(range); // [1, 2, 3, 4, 5]Manipulate the sequence
import { ExtraIterator } from 'extra-iterator';
const result = ExtraIterator.concat([1, 2, 3], [4, 5, 6])
.dropWhile(n => n < 3)
.take(3)
.loop(4)
.toArray();
console.log(result); // [3, 4, 5, 3, 4, 5, 3, 4, 5, 3, 4, 5]Map an object's key-values pairs
import { ExtraIterator } from 'extra-iterator';
const example = {
first: 1,
second: 2,
third: 3,
};
const result = ExtraIterator.from(Object.entries(example))
.append(['fourth', 4])
.interposeWith(([leftKey, leftValue], [rightKey, rightValue]) =>
[`${leftKey}_${rightKey}`, (leftValue + rightValue) / 2]
)
.collect(Object.fromEntries);
console.log(result);
// {
// first: 1,
// first_second: 1.5,
// second: 2,
// second_third: 2.5,
// third: 3,
// third_fourth: 3.5,
// fourth: 4
// }Use ExtraIterator.from() to wrap an iterable, iterator, or array-like object
import { ExtraIterator } from 'extra-iterator';
const fromIterable = ExtraIterator.from(new Set([1, 2, 3]));
const fromGenerator = ExtraIterator.from(function*() {
yield 'a';
yield 'b';
}());
const fromArrayLike = ExtraIterator.from({ 0: 'x', 1: 'y', length: 2 });
console.log(fromGenerator.toArray()); // ['a', 'b']
console.log(fromArrayLike.toArray()); // ['x', 'y']Laziness and consumption
Transformation methods are lazy. Nothing happens until you consume the iterator.
const iter = ExtraIterator.from([1, 2, 3])
.map(value => value * 2)
.withEach(value => console.log('seen:', value));
// No output yet.
console.log(iter.take(2).toArray());
// seen: 2
// seen: 4
// [2, 4]Like native iterators, ExtraIterator instances are generally one-shot. Once consumed, the values are gone unless you
create a new iterator.
Work with infinite sequences
import { ExtraIterator } from 'extra-iterator';
const evens = ExtraIterator.count({ start: 0, increment: 2 })
.take(5)
.toArray();
console.log(evens); // [0, 2, 4, 6, 8]Flatten nested arrays
import { ExtraIterator } from 'extra-iterator';
const values = ExtraIterator.from([0, [1, [2, [3, 4]]], [5, [6]], 7])
.flat()
.toArray();
console.log(values); // [0, 1, 2, 3, 4, 5, 6, 7]Group adjacent values into chunks
import { ExtraIterator } from 'extra-iterator';
const chunks = ExtraIterator.from([1, 1, 2, 3, 3, 3, 2, 2])
.chunkWith((left, right) => left === right)
.toArray();
console.log(chunks); // [[1, 1], [2], [3, 3, 3], [2, 2]]Find the nearest common ancestor between all DOM paragraph elements
import { ExtraIterator } from 'extra-iterator';
const commonAncestor = ExtraIterator.from(document.querySelectorAll('p'))
.map(element => ExtraIterator.from(function*() {
for (let node = element.parentNode; node; node = node.parentNode) {
yield node;
}
}()))
.map(ancestorList => ancestorList.toArray().reverse())
.zip()
.takeWhile(nodes => new Set(nodes).size === 1)
.last()
.first();API overview
See full API documentation at: leonardoraele.github.io/extra-iterator
Static constructors
ExtraIterator.from(source)- Iterates over any iterable object or array-like object.ExtraIterator.empty()- Creates an empty iterator.ExtraIterator.single(value)- Creates an iterator with a single value.ExtraIterator.count()- An infinite incremental number iterator.ExtraIterator.range(start, end)- Iterates over a specific range.ExtraIterator.repeat(value)- An iterator that repeats a single value infinitely.ExtraIterator.random()- An iterator that yields infinite random numbers.ExtraIterator.randomBytes()- An iterator that yields infinite chunks of random bytes.ExtraIterator.zip(...sources)- Iterates over multiple sequences simultaneously.
Standard iterator helpers that remain chainable
These native iterator-helper methods work just like the built-in methods, but return chainable ExtraIterator instances instead of built-in Iterator objects.
filter()flatMap()map()take()drop()
take() and drop() also support negative counts:
take(n)keeps the firstnelements of the iterator (or the last ones ifnis negative), and discard the rest.drop(n)discards the firstnelements (or the last ones ifnis negative), and keep the rest.
Transformation helpers
flat()- Similar toArray.prototype.flat(), but recursive.unique()- Filters repeated elements out of the iterator.compact()- Filtersnullandundefinedvalues out of the iterator.append(value)- Appends one value to the end of the iterator.prepend(value)- Prepends one value to the beginning of the iterator.concat(iterable)- Concatenates multiple values to the end of the iterator.prependAll(iterable)- Prepends multiple values to the beginning of the iterator.takeWhile(predicate)- Similar toIterator.prototype.take(), but with a condition instead of a fixed count.dropWhile(predicate)- Similar toIterator.prototype.drop(), but with a condition instead of a fixed count.chunk(size)- Groups the elements into chunks of fixed size.chunkWith(predicate)- Groups adjacent elements based on a predicate function.zip(others)- Creates a new iterator that yields the values of this and the other iterators in tuples.interpose(separator)- Adds a separator value between each pair of adjacent elements.interposeWith(separatorProvider)- Adds a separate value between each pair of elements based on a function.interleave(other)- Interleave the values of this iterator with those of another iterator.splice(startIndex, deleteCount, ...newItems)- Similar toArray.prototype.splice().defaultIfEmpty(provider)- If the iterator is empty, adds a default value to it.loop(n = Infinity)- Expands the iterator by repeating its valuesntimes.withEach(callback)- Similar toIterator.prototype.forEach(), but returnsthisiterator.
Aggregation helpers
These methods consume the iterator and return a final value instead of another iterator:
first()- Returns the first value orundefinedif empty.last()- Returns the last value orundefinedif empty.at(index)- Returns the value at the index, orundefined.groupBy(callback)- Similar toObject.groupBy().toMap(callback)- Similar toMap.groupBy().toSet()- Creates aSetobject with the elements of this iterator.toChainOfResponsibilityFunction(invokeHandler)collect(callback)- Reduce the iterator to a single value by calling a callback function.sum()- Sum all numbers in the iterator.count()- Returns the number of elements in the iterator.testUnique()- Checks whether the iterator has duplicated elements.
You also still have the native consuming helpers provided by iterator helpers, such as reduce(), some(), every(),
find(), forEach(), and toArray().
Optional [toExtra]() helper
An optional, chainable helper method that transforms any iterable object into an ExtraIterator.
import { toExtra } from 'extra-iterator/to-extra';
const result = [1, 2, 3]
[toExtra]() // The `[toExtra]()` method transforms the built-in array into an `ExtraIterator` object...
.prepend(0) // Allowing you to chain into the new helper methods:
.splice(2, 0, 0.5)
.drop(-2)
.loop(3)
.toArray();
console.log(result);
// [0, 0.5, 1, 0, 0.5, 1, 0, 0.5, 1]By importing the optional extra-iterator/to-extra submodule, you opt-in to expanding the global Object prototype
with the [toExtra]() method as a side-effect.
This side-effect is optional. If you don't want to "polute" the global prototypes, you can still use this package as
normal. Simply don't import extra-iterator/to-extra and the global prototypes will remain unchanged.
License
This project is licensed under the MIT License. See the LICENSE.txt file for the full license text.
