Important
Please participate in the survey here!
(open until end of February)
To achieve a better sample size, I'd highly appreciate if you could circulate the link to this survey in your own networks.
Note
This is one of 189 standalone projects, maintained as part of the @thi.ng/umbrella monorepo and anti-framework.
🚀 Help me to work full-time on these projects by sponsoring me on GitHub. Thank you! ❤️
Various implementations of the @thi.ng/api
ISeq
interface / sequence abstraction and related tooling (inspired by
Clojure). Think of ISeq
s as readonly sequential views & cursors of an
underlying (not necessarily sequential) collection...
Unlike with ES6 iterators,
ISeq.next()
is decoupled from an iteration step and merely produces a new view /
sequence head of the remaining sequence values. This allows forking &
sharing the sequence head(s) among multiple consumers, each able to read
the remaining values at their own pace.
ALPHA - bleeding edge / work-in-progress
Search or submit any issues for this package
yarn add @thi.ng/seq
ES module import:
<script type="module" src="https://cdn.skypack.dev/@thi.ng/seq"></script>
For Node.js REPL:
const seq = await import("@thi.ng/seq");
Package sizes (brotli'd, pre-treeshake): ESM: 533 bytes
import { aseq, rseq, concat, iterator } from "@thi.ng/seq";
// create a sequence abstraction of an array
const a = aseq([1,2,3]);
// aseq returns `undefined` for nullish or empty array arguments
// this is in accordance w/ the `ISeqable` interface
// see further below...
aseq([])
// undefined
// first() returns first value of seq (or undefined if empty)
a.first()
// 1
// next() returns new seq of remaining items
a.next()
// { first: [Function: first], next: [Function: next] }
a.next().first();
// 2
a.next().next().first();
// 3
// if the resulting sub-sequence is empty, next() returns undefined
a.next().next().next();
// undefined
// aseq() can take optional index range args
aseq([10, 20, 30, 40], 2).first()
// 30
aseq([10, 20, 30, 40], 2).next().first()
// 40
// the iterator here is only used for demo purposes
// (i.e. to convert the sequence to a standard ES6 iterable & show the result)
[...iterator(aseq([10, 20, 30, 40], 2))]
// [30, 40]
// rseq() produces a reverse sequence of the given array
rseq([1, 2, 3]).first()
// 3
rseq([1, 2, 3]).next().first()
// 2
// index ranges only (start MUST be > end)
[...iterator(rseq([0, 1, 2, 3, 4], 2))]
// [2, 1, 0]
[...iterator(rseq([0, 1, 2, 3, 4], 3, 1))]
// [3, 2]
// values can be prepended via cons()
[...iterator(cons(42, aseq([1, 2, 3])))]
// [ 42, 1, 2, 3 ]
// create new (or single value) seqs
cons(42).first()
// 42
cons(42).next()
// undefined
// zero-copy concat (supporting nullable parts/sub-sequences)
[...iterator(concat(null, aseq([]), aseq([1, 2]), undefined, cons(3)))]
// [ 1, 2, 3 ]
// if only arrays are used as sources, can also use concatA()
[...iterator(concatA(null, [], [1, 2], undefined, [3]))]
// [ 1, 2, 3 ]
Since the entire approach is interface based, sequences can be defined for any custom datatype (preferably via the ISeqable interface), for example here using @thi.ng/dcons:
import { dcons } from "@thi.ng/dcons";
// concat reversed array with doubly-linked list
[...iterator(concat(rseq([1, 2, 3]), dcons([4, 5, 6])))]
// [ 3, 2, 1, 4, 5, 6 ]
Lazily instantiated (possibly infinite) sequences can be created via
lazyseq()
. This function returns an ISeq
which only realizes its
values when they're requested.
import { defmultiN } from "@thi.ng/defmulti";
// defmultiN only used here to define multiple arities for `fib`
const fib = defmultiN({
0: () => fib(0, 1),
2: (a, b) => lazyseq(() => {
console.log(`realize: ${a}`);
return cons(a, fib(b, a + b));
})
});
fib()
// { first: [Function: first], next: [Function: next] }
fib().first()
// realize: 0
// 0
fib().next().first()
// realize: 0
// realize: 1
// 1
fib().next().next().first()
// realize: 0
// realize: 1
// realize: 1
// 1
fib().next().next().next().first()
// realize: 0
// realize: 1
// realize: 1
// realize: 2
// 2
fib().next().next().next().next().first()
// realize: 0
// realize: 1
// realize: 1
// realize: 2
// realize: 3
// 3
If this project contributes to an academic publication, please cite it as:
@misc{thing-seq,
title = "@thi.ng/seq",
author = "Karsten Schmidt",
note = "https://thi.ng/seq",
year = 2019
}
© 2019 - 2024 Karsten Schmidt // Apache License 2.0