Functional tree editing, manipulation & navigation
npm install @thi.ng/zipper
!npm downloads

> [!NOTE]
> This is one of 214 standalone projects, maintained as part
> of the @thi.ng/umbrella monorepo
> and anti-framework.
>
> 🚀 Please help me to work full-time on these projects by sponsoring me on
> GitHub. Thank you! ❤️
- About
- Status
- Related packages
- Blog posts
- Installation
- Dependencies
- API
- Benchmark
- Authors
- License
Functional tree editing, manipulation & navigation.
Immutable, semi-functional, structural tree editing, manipulation &
navigation, based on my fork and optimizations to
fast-zip, which in turn
is based on
clojure.zip
and which itself is based on the original data structure invented by
Gérard Huet in 1997.
Reference: https://en.wikipedia.org/wiki/Zipper_(data_structure)
STABLE - used in production
Search or submit any issues for this package
- @thi.ng/gp - Genetic programming helpers & strategies (tree based & multi-expression programming)
- Evolutionary failures (Part 1)
``bash`
yarn add @thi.ng/zipper
ESM import:
`ts`
import * as zip from "@thi.ng/zipper";
Browser ESM import:
`html`
For Node.js REPL:
`js`
const zip = await import("@thi.ng/zipper");
Package sizes (brotli'd, pre-treeshake): ESM: 1.02 KB
- @thi.ng/api
- @thi.ng/arrays
- @thi.ng/checks
- @thi.ng/errors
Note: @thi.ng/api is in _most_ cases a type-only import (not used at runtime)
`ts
import { arrayZipper } from "@thi.ng/zipper";
const x = [1, [5, 4, 3, 2], 6];
// create zipper for given array
const a = arrayZipper(x);
// .next navigates to logically next location (depth-first)
// .node retrieves a location's value
a.next.node
// 1
a.next.next.node
// [5, 4, 3, 2]
// all navigation verbs:
// prev, left, right, up, down, leftmost, rightmost
a.next.next.down.rightmost.node
// 2
// navigate to value 3, remove it7
// then append at top level
// and apply changes by requesting root value
// (the latter is the actual zip operation)
a.next.next.down.rightmost.left.remove().up.up.appendChild(7).root
// [ 1, [ 5, 4, 2 ], 6, 7 ]
// the same edits in different order
a.appendChild(7).next.next.down.rightmost.left.remove().root
// [ 1, [ 5, 4, 2 ], 6, 7 ]
// insert child at the front
a.next.next.insertChild(10).root
// [ 1, [ 10, 5, 4, 3, 2 ], 6 ]
// replace the nested array
a.next.next.replace(10).root
// [1, 10, 6]
// all editing is immutable, original is untouched...
x
// [ 1, [ 5, 4, 3, 2 ], 6 ]
`
For better comparison, the included benchmarks are also ported from the
fast-zip package and
measure traversal & editing of a tree of 10 x 10 x 10 values.
Measurements for MBP 2015 2.8GHz, 16GB, node v12.10.0:
`text
$ node bench/index.js
walk:
warmup... 2562ms
warmup... 2469ms
warmup... 2460ms
total: 2476ms, mean: 0.2476ms, runs: 10000
edit:
warmup... 4660ms
warmup... 4573ms
warmup... 4566ms
total: 4616ms, mean: 0.4616ms, runs: 10000
`
If this project contributes to an academic publication, please cite it as:
`bibtex``
@misc{thing-zipper,
title = "@thi.ng/zipper",
author = "Karsten Schmidt",
note = "https://thi.ng/zipper",
year = 2015
}
© 2015 - 2026 Karsten Schmidt // Apache License 2.0