@thi.ng/trie 1.1.29 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -1
- package/README.md +34 -20
- package/multi-trie.d.ts +38 -23
- package/multi-trie.js +73 -62
- package/package.json +9 -4
- package/trie-map.d.ts +19 -8
- package/trie-map.js +41 -42
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2025-08-
|
|
3
|
+
- **Last updated**: 2025-08-11T16:41:24Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -11,6 +11,27 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
11
11
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
12
12
|
and/or version bumps of transitive dependencies.
|
|
13
13
|
|
|
14
|
+
# [2.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/trie@2.0.0) (2025-08-11)
|
|
15
|
+
|
|
16
|
+
#### 🛑 Breaking changes
|
|
17
|
+
|
|
18
|
+
- major update `TrieMap` & `MultiTrie` ([d7f4a12](https://github.com/thi-ng/umbrella/commit/d7f4a12))
|
|
19
|
+
- BREAKING CHANGE: major update `TrieMap` & `MultiTrie`
|
|
20
|
+
- update `MultiTrie` to only support array-based keys
|
|
21
|
+
- switch internals to using Map for storing branches
|
|
22
|
+
- update arg types in all methods
|
|
23
|
+
- add `.toJSON()` method to support serialization
|
|
24
|
+
- rename `MultiTrieOpts.vals` => `.values`
|
|
25
|
+
- add/update/dedupe iterators in both impls
|
|
26
|
+
- replace `.suffixes()` iterator in both impls w/ extra args passed to `.keys()`
|
|
27
|
+
- add `defTrieMapFromJSON()` and `defMultiTrieFromJSON()`
|
|
28
|
+
- add/update tests
|
|
29
|
+
|
|
30
|
+
#### ♻️ Refactoring
|
|
31
|
+
|
|
32
|
+
- update internals ([065cc27](https://github.com/thi-ng/umbrella/commit/065cc27))
|
|
33
|
+
- remove obsolete size/count in MultiTrie
|
|
34
|
+
|
|
14
35
|
### [1.1.10](https://github.com/thi-ng/umbrella/tree/@thi.ng/trie@1.1.10) (2025-01-14)
|
|
15
36
|
|
|
16
37
|
#### ♻️ Refactoring
|
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
## About
|
|
29
29
|
|
|
30
|
-
Trie-based
|
|
30
|
+
Trie-based ES6-like Map data structures with prefix search/query support.
|
|
31
31
|
|
|
32
32
|
This package contains functionality which was previously part of and has been
|
|
33
33
|
extracted from the [@thi.ng/associative](https://thi.ng/associative) package.
|
|
@@ -42,9 +42,10 @@ prefix, longest matching prefix queries etc.
|
|
|
42
42
|
The implementations here too feature ES6 Map-like API, similar to other types in
|
|
43
43
|
this package, with some further trie-specific additions.
|
|
44
44
|
|
|
45
|
-
```ts
|
|
46
|
-
import { defTrieMap } from "@thi.ng/
|
|
45
|
+
```ts tangle:export/readme-1.ts
|
|
46
|
+
import { defTrieMap } from "@thi.ng/trie";
|
|
47
47
|
|
|
48
|
+
// construct trie from given key-value pairs (optional)
|
|
48
49
|
const trie = defTrieMap([
|
|
49
50
|
["hey", "en"],
|
|
50
51
|
["hello", "en"],
|
|
@@ -55,42 +56,55 @@ const trie = defTrieMap([
|
|
|
55
56
|
["hej", "se"],
|
|
56
57
|
]);
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
// find longest known prefix given key
|
|
60
|
+
console.log(trie.knownPrefix("hole"));
|
|
59
61
|
// "hol"
|
|
60
62
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
// all known keys
|
|
64
|
+
console.log([...trie.keys()])
|
|
65
|
+
// [ "hold", "hola", "hallo", "hej", "hello", "hey" ]
|
|
63
66
|
|
|
64
|
-
//
|
|
65
|
-
[...trie.
|
|
67
|
+
// all keys starting with given prefix
|
|
68
|
+
console.log([...trie.keys("he")])
|
|
66
69
|
// [ "hej", "hello", "hey" ]
|
|
70
|
+
|
|
71
|
+
// suffixes of given key only
|
|
72
|
+
console.log([...trie.keys("he", false)])
|
|
73
|
+
// [ "j", "llo", "y" ]
|
|
74
|
+
|
|
75
|
+
// values of keys starting with prefix
|
|
76
|
+
console.log([...trie.values("hol")]);
|
|
77
|
+
// [ "en", "es" ]
|
|
67
78
|
```
|
|
68
79
|
|
|
69
80
|
### MultiTrie
|
|
70
81
|
|
|
71
|
-
The `MultiTrie` is similar to `TrieMap`, but
|
|
82
|
+
The `MultiTrie` is similar to `TrieMap`, but uses array-like keys and supports
|
|
72
83
|
multiple values per key. Values are stored in sets whose implementation can be
|
|
73
|
-
configured via ctor options.
|
|
84
|
+
configured via ctor options (e.g. using custom ES6-like Sets with value-based
|
|
85
|
+
equality semantics from the [thi.ng/associative](https://thi.ng/associative)
|
|
86
|
+
package).
|
|
74
87
|
|
|
75
|
-
```ts
|
|
76
|
-
import { defMultiTrie } from "@thi.ng/
|
|
88
|
+
```ts tangle:export/readme-2.ts
|
|
89
|
+
import { defMultiTrie } from "@thi.ng/trie";
|
|
90
|
+
import { ArraySet } from "@thi.ng/associative";
|
|
77
91
|
|
|
78
|
-
// init w/ custom value set type (here
|
|
79
|
-
const t = defMultiTrie<string
|
|
92
|
+
// init w/ custom value set type (here purely for illustration)
|
|
93
|
+
const t = defMultiTrie<string, string>(null, { values: () => new ArraySet() });
|
|
80
94
|
|
|
81
95
|
t.add("to be or not to be".split(" "), 1);
|
|
82
96
|
t.add("to be or not to be".split(" "), 2);
|
|
83
97
|
t.add("to be and to live".split(" "), 3);
|
|
84
98
|
|
|
85
|
-
t.get("to be or not to be".split(" "))
|
|
99
|
+
console.log(t.get("to be or not to be".split(" ")))
|
|
86
100
|
// Set(2) { 1, 2 }
|
|
87
101
|
|
|
88
|
-
t.knownPrefix(["to", "be", "not"]);
|
|
102
|
+
console.log(t.knownPrefix(["to", "be", "not"]));
|
|
89
103
|
// [ "to", "be" ]
|
|
90
104
|
|
|
91
|
-
//
|
|
92
|
-
[...t.
|
|
93
|
-
// [ "
|
|
105
|
+
// suffixes for given prefix
|
|
106
|
+
console.log([...t.keys(["to", "be"], false)]);
|
|
107
|
+
// [["and", "to", "live"], ["or", "not", "to", "be"]]
|
|
94
108
|
```
|
|
95
109
|
|
|
96
110
|
## Status
|
|
@@ -129,7 +143,7 @@ For Node.js REPL:
|
|
|
129
143
|
const trie = await import("@thi.ng/trie");
|
|
130
144
|
```
|
|
131
145
|
|
|
132
|
-
Package sizes (brotli'd, pre-treeshake): ESM: 1.
|
|
146
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 1.14 KB
|
|
133
147
|
|
|
134
148
|
## Dependencies
|
|
135
149
|
|
package/multi-trie.d.ts
CHANGED
|
@@ -1,39 +1,54 @@
|
|
|
1
|
-
import type { Fn0,
|
|
1
|
+
import type { Fn0, Fn2, Maybe, Nullable, Pair } from "@thi.ng/api";
|
|
2
2
|
export interface MultiTrieOpts<V> {
|
|
3
3
|
/**
|
|
4
|
-
* Custom value set factory (e.g.
|
|
4
|
+
* Custom value set factory (e.g. `Set` implementations from the
|
|
5
5
|
* [thi.ng/associative](https://thi.ng/associative) package). Uses native
|
|
6
6
|
* ES6 Set by default.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
values: Fn0<Set<V>>;
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Multi-Map-like trie implementation for array-based keys and supporting
|
|
12
|
+
* multiple unique values per key.
|
|
13
|
+
*/
|
|
14
|
+
export declare class MultiTrie<K, V> {
|
|
11
15
|
protected opts?: Partial<MultiTrieOpts<V>> | undefined;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
[
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
suffixes(prefix: K, withPrefix?: boolean, sep?: string): Generator<string, void, unknown>;
|
|
16
|
+
next: Map<K, MultiTrie<K, V>>;
|
|
17
|
+
vals?: Set<V>;
|
|
18
|
+
constructor(pairs?: Nullable<Iterable<Pair<K[], V>>>, opts?: Partial<MultiTrieOpts<V>> | undefined);
|
|
19
|
+
[Symbol.iterator](): Generator<Pair<K, V>, void, any>;
|
|
20
|
+
keys(prefix?: K[], includePrefix?: boolean): Generator<K[], void, any>;
|
|
21
|
+
values(prefix?: K[]): Generator<V, void, any>;
|
|
22
|
+
entries(prefix?: K[], includePrefix?: boolean): Generator<Pair<K, V>, void, any>;
|
|
20
23
|
clear(): void;
|
|
21
|
-
has(key: K): boolean;
|
|
22
|
-
hasPrefix(prefix: K): boolean;
|
|
23
|
-
get(key: K): Maybe<Set<V>>;
|
|
24
|
-
find(key: K): MultiTrie<K, V> | undefined;
|
|
24
|
+
has(key: K[]): boolean;
|
|
25
|
+
hasPrefix(prefix: K[]): boolean;
|
|
26
|
+
get(key: K[]): Maybe<Set<V>>;
|
|
27
|
+
find(key: K[]): MultiTrie<K, V> | undefined;
|
|
25
28
|
/**
|
|
26
29
|
* Returns longest known prefix for `key` as array. If array is
|
|
27
30
|
* empty, the given key has no partial matches.
|
|
28
31
|
*
|
|
29
32
|
* @param key -
|
|
30
33
|
*/
|
|
31
|
-
knownPrefix(key: K): K[];
|
|
32
|
-
hasKnownPrefix(key: K): boolean;
|
|
33
|
-
add(key: K, val: V): void;
|
|
34
|
-
into(pairs: Iterable<[K, V]>): void;
|
|
35
|
-
delete(prefix: K, val?: V): boolean;
|
|
36
|
-
|
|
34
|
+
knownPrefix(key: K[]): K[];
|
|
35
|
+
hasKnownPrefix(key: K[]): boolean;
|
|
36
|
+
add(key: K[], val: V): void;
|
|
37
|
+
into(pairs: Iterable<[K[], V]>): void;
|
|
38
|
+
delete(prefix: K[], val?: V): boolean;
|
|
39
|
+
toJSON(): SerializedMultiTrie<V>;
|
|
40
|
+
protected iterate<T>(fn: Fn2<K[], MultiTrie<K, V>, Iterable<T>>, prefix?: K[], includePrefix?: boolean): Generator<T, void, any>;
|
|
37
41
|
}
|
|
38
|
-
export declare const defMultiTrie: <K
|
|
42
|
+
export declare const defMultiTrie: <K, V>(pairs?: Nullable<Iterable<Pair<K[], V>>>, opts?: Partial<MultiTrieOpts<V>>) => MultiTrie<K, V>;
|
|
43
|
+
export type SerializedMultiTrie<V> = {
|
|
44
|
+
next: Record<string, SerializedMultiTrie<V>>;
|
|
45
|
+
vals?: any[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Reconstruct a {@link MultiTrie} from serialized JSON.
|
|
49
|
+
*
|
|
50
|
+
* @param src
|
|
51
|
+
* @param opts
|
|
52
|
+
*/
|
|
53
|
+
export declare const defMultiTrieFromJSON: <V>(src: SerializedMultiTrie<V>, opts?: Partial<MultiTrieOpts<V>>) => MultiTrie<string, V>;
|
|
39
54
|
//# sourceMappingURL=multi-trie.d.ts.map
|
package/multi-trie.js
CHANGED
|
@@ -3,54 +3,28 @@ class MultiTrie {
|
|
|
3
3
|
this.opts = opts;
|
|
4
4
|
pairs && this.into(pairs);
|
|
5
5
|
}
|
|
6
|
-
next =
|
|
6
|
+
next = /* @__PURE__ */ new Map();
|
|
7
7
|
vals;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const [prefix, node] = queue.pop();
|
|
13
|
-
if (node.vals) {
|
|
14
|
-
for (let v of node.vals) yield [prefix, v];
|
|
15
|
-
} else {
|
|
16
|
-
node.queueChildren(queue, prefix);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
8
|
+
[Symbol.iterator]() {
|
|
9
|
+
return this.iterate(
|
|
10
|
+
(key, node) => [...node.vals].map((v) => [key, v])
|
|
11
|
+
);
|
|
19
12
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
while (queue.length) {
|
|
23
|
-
const [key, node] = queue.pop();
|
|
24
|
-
if (node.vals) {
|
|
25
|
-
yield key;
|
|
26
|
-
} else {
|
|
27
|
-
node.queueChildren(queue, key, sep);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
13
|
+
keys(prefix = [], includePrefix = true) {
|
|
14
|
+
return this.iterate((key) => [key], prefix, includePrefix);
|
|
30
15
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
while (queue.length) {
|
|
34
|
-
const node = queue.pop();
|
|
35
|
-
if (node.vals) {
|
|
36
|
-
yield* node.vals;
|
|
37
|
-
} else {
|
|
38
|
-
queue.push(...Object.values(node.next));
|
|
39
|
-
}
|
|
40
|
-
}
|
|
16
|
+
values(prefix) {
|
|
17
|
+
return this.iterate((_, node) => node.vals, prefix);
|
|
41
18
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
);
|
|
49
|
-
}
|
|
19
|
+
entries(prefix, includePrefix = true) {
|
|
20
|
+
return this.iterate(
|
|
21
|
+
(key, node) => [...node.vals].map((v) => [key, v]),
|
|
22
|
+
prefix,
|
|
23
|
+
includePrefix
|
|
24
|
+
);
|
|
50
25
|
}
|
|
51
26
|
clear() {
|
|
52
|
-
this.next
|
|
53
|
-
this.n = 0;
|
|
27
|
+
this.next.clear();
|
|
54
28
|
this.vals = void 0;
|
|
55
29
|
}
|
|
56
30
|
has(key) {
|
|
@@ -66,7 +40,7 @@ class MultiTrie {
|
|
|
66
40
|
find(key) {
|
|
67
41
|
let node = this;
|
|
68
42
|
for (let i = 0, n = key.length; i < n; i++) {
|
|
69
|
-
node = node.next
|
|
43
|
+
node = node.next.get(key[i]);
|
|
70
44
|
if (!node) return;
|
|
71
45
|
}
|
|
72
46
|
return node;
|
|
@@ -81,8 +55,8 @@ class MultiTrie {
|
|
|
81
55
|
let node = this;
|
|
82
56
|
const prefix = [];
|
|
83
57
|
for (let i = 0, n = key.length; i < n; i++) {
|
|
84
|
-
const k = key[i]
|
|
85
|
-
const next = node.next
|
|
58
|
+
const k = key[i];
|
|
59
|
+
const next = node.next.get(k);
|
|
86
60
|
if (!next) break;
|
|
87
61
|
prefix.push(k);
|
|
88
62
|
node = next;
|
|
@@ -95,13 +69,18 @@ class MultiTrie {
|
|
|
95
69
|
add(key, val) {
|
|
96
70
|
let node = this;
|
|
97
71
|
for (let i = 0, n = key.length; i < n; i++) {
|
|
98
|
-
const k = key[i]
|
|
99
|
-
const next = node.next
|
|
100
|
-
|
|
72
|
+
const k = key[i];
|
|
73
|
+
const next = node.next.get(k);
|
|
74
|
+
if (!next) {
|
|
75
|
+
const newNode = new MultiTrie(null, this.opts);
|
|
76
|
+
node.next.set(k, newNode);
|
|
77
|
+
node = newNode;
|
|
78
|
+
} else {
|
|
79
|
+
node = next;
|
|
80
|
+
}
|
|
101
81
|
}
|
|
102
82
|
if (!node.vals) {
|
|
103
|
-
|
|
104
|
-
node.vals = ctor ? ctor() : /* @__PURE__ */ new Set();
|
|
83
|
+
node.vals = this.opts?.values?.() ?? /* @__PURE__ */ new Set();
|
|
105
84
|
}
|
|
106
85
|
node.vals.add(val);
|
|
107
86
|
}
|
|
@@ -118,10 +97,10 @@ class MultiTrie {
|
|
|
118
97
|
let i = 0;
|
|
119
98
|
let node = this;
|
|
120
99
|
for (; i < n; i++) {
|
|
121
|
-
const k = prefix[i]
|
|
100
|
+
const k = prefix[i];
|
|
122
101
|
key.push(k);
|
|
123
102
|
path.push(node);
|
|
124
|
-
node = node.next
|
|
103
|
+
node = node.next.get(k);
|
|
125
104
|
if (!node) return false;
|
|
126
105
|
}
|
|
127
106
|
if (val !== void 0) {
|
|
@@ -134,22 +113,54 @@ class MultiTrie {
|
|
|
134
113
|
}
|
|
135
114
|
}
|
|
136
115
|
while (node = path[--i]) {
|
|
137
|
-
|
|
138
|
-
if (
|
|
116
|
+
node.next.delete(key[i]);
|
|
117
|
+
if (node.next.size) break;
|
|
139
118
|
}
|
|
140
119
|
return true;
|
|
141
120
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
)
|
|
148
|
-
|
|
121
|
+
toJSON() {
|
|
122
|
+
return {
|
|
123
|
+
next: [...this.next].reduce(
|
|
124
|
+
(acc, [k, v]) => (acc[k] = v.toJSON(), acc),
|
|
125
|
+
{}
|
|
126
|
+
),
|
|
127
|
+
vals: this.vals ? [...this.vals] : void 0
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
*iterate(fn, prefix = [], includePrefix = true) {
|
|
131
|
+
const root = this.find(prefix);
|
|
132
|
+
if (!root) return;
|
|
133
|
+
const queue = [
|
|
134
|
+
[includePrefix ? prefix : [], root]
|
|
135
|
+
];
|
|
136
|
+
while (queue.length) {
|
|
137
|
+
const [key, node] = queue.pop();
|
|
138
|
+
if (node.vals) yield* fn(key, node);
|
|
139
|
+
queue.push(
|
|
140
|
+
...[...node.next].map(
|
|
141
|
+
([k, v]) => [key.concat(k), v]
|
|
142
|
+
)
|
|
143
|
+
);
|
|
144
|
+
}
|
|
149
145
|
}
|
|
150
146
|
}
|
|
151
147
|
const defMultiTrie = (pairs, opts) => new MultiTrie(pairs, opts);
|
|
148
|
+
const defMultiTrieFromJSON = (src, opts) => {
|
|
149
|
+
const res = defMultiTrie(null, opts);
|
|
150
|
+
const queue = [[[], src]];
|
|
151
|
+
while (queue.length) {
|
|
152
|
+
const [key, node] = queue.pop();
|
|
153
|
+
if (node.vals) {
|
|
154
|
+
for (let v of node.vals) res.add(key, v);
|
|
155
|
+
}
|
|
156
|
+
for (let [k, child] of Object.entries(node.next)) {
|
|
157
|
+
queue.push([[...key, k], child]);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return res;
|
|
161
|
+
};
|
|
152
162
|
export {
|
|
153
163
|
MultiTrie,
|
|
154
|
-
defMultiTrie
|
|
164
|
+
defMultiTrie,
|
|
165
|
+
defMultiTrieFromJSON
|
|
155
166
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/trie",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Trie-based
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Trie-based ES6-like Map data structures with prefix search/query support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
7
7
|
"typings": "./index.d.ts",
|
|
@@ -47,13 +47,18 @@
|
|
|
47
47
|
"typescript": "^5.9.2"
|
|
48
48
|
},
|
|
49
49
|
"keywords": [
|
|
50
|
+
"associative",
|
|
50
51
|
"datastructure",
|
|
51
|
-
"equality",
|
|
52
52
|
"iterator",
|
|
53
53
|
"keys",
|
|
54
54
|
"map",
|
|
55
55
|
"prefix",
|
|
56
56
|
"query",
|
|
57
|
+
"search",
|
|
58
|
+
"set",
|
|
59
|
+
"string",
|
|
60
|
+
"text",
|
|
61
|
+
"tree",
|
|
57
62
|
"trie",
|
|
58
63
|
"typescript"
|
|
59
64
|
],
|
|
@@ -88,5 +93,5 @@
|
|
|
88
93
|
],
|
|
89
94
|
"year": 2020
|
|
90
95
|
},
|
|
91
|
-
"gitHead": "
|
|
96
|
+
"gitHead": "f6ebc1302dc9211d588293aa0897173c6e54f4e5\n"
|
|
92
97
|
}
|
package/trie-map.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import type { IObjectOf, Maybe, Pair } from "@thi.ng/api";
|
|
1
|
+
import type { Fn2, IObjectOf, Maybe, Pair } from "@thi.ng/api";
|
|
2
2
|
export declare class TrieMap<T> {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
next: IObjectOf<TrieMap<T>>;
|
|
4
|
+
val?: T;
|
|
5
5
|
protected n: number;
|
|
6
6
|
constructor(pairs?: Iterable<Pair<string, T>>);
|
|
7
|
-
[Symbol.iterator](): Generator<
|
|
8
|
-
keys(prefix?: string): Generator<string, void, unknown>;
|
|
9
|
-
values(): Generator<T
|
|
10
|
-
|
|
7
|
+
[Symbol.iterator](): Generator<Pair<string, T>, void, unknown>;
|
|
8
|
+
keys(prefix?: string, includePrefix?: boolean): Generator<string, void, unknown>;
|
|
9
|
+
values(prefix?: string): Generator<NonNullable<T>, void, unknown>;
|
|
10
|
+
entries(prefix?: string, includePrefix?: boolean): Generator<Pair<string, T>, void, unknown>;
|
|
11
11
|
clear(): void;
|
|
12
12
|
has(key: string): boolean;
|
|
13
13
|
hasPrefix(prefix: string): boolean;
|
|
@@ -24,7 +24,18 @@ export declare class TrieMap<T> {
|
|
|
24
24
|
set(key: string, val: T): void;
|
|
25
25
|
into(pairs: Iterable<Pair<string, T>>): void;
|
|
26
26
|
delete(prefix: string): boolean;
|
|
27
|
-
protected
|
|
27
|
+
protected iterate<V>(fn: Fn2<string, TrieMap<T>, V>, prefix?: string, includePrefix?: boolean): Generator<V, void, unknown>;
|
|
28
28
|
}
|
|
29
29
|
export declare const defTrieMap: <T>(pairs?: Iterable<Pair<string, T>>) => TrieMap<T>;
|
|
30
|
+
export type SerializedTrieMap<T> = {
|
|
31
|
+
next: IObjectOf<SerializedTrieMap<T>>;
|
|
32
|
+
val?: T;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Reconstruct a {@link MultiTrie} from serialized JSON.
|
|
36
|
+
*
|
|
37
|
+
* @param src
|
|
38
|
+
* @param opts
|
|
39
|
+
*/
|
|
40
|
+
export declare const defTrieMapFromJSON: <V>(src: SerializedTrieMap<V>) => TrieMap<V>;
|
|
30
41
|
//# sourceMappingURL=trie-map.d.ts.map
|
package/trie-map.js
CHANGED
|
@@ -5,44 +5,21 @@ class TrieMap {
|
|
|
5
5
|
constructor(pairs) {
|
|
6
6
|
pairs && this.into(pairs);
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
while (queue.length) {
|
|
11
|
-
const [prefix, node] = queue.pop();
|
|
12
|
-
if (node.val !== void 0) {
|
|
13
|
-
yield [prefix, node.val];
|
|
14
|
-
} else {
|
|
15
|
-
node.queueChildren(queue, prefix);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
8
|
+
[Symbol.iterator]() {
|
|
9
|
+
return this.iterate((key, node) => [key, node.val]);
|
|
18
10
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
while (queue.length) {
|
|
22
|
-
const [key, node] = queue.pop();
|
|
23
|
-
if (node.val !== void 0) {
|
|
24
|
-
yield key;
|
|
25
|
-
} else {
|
|
26
|
-
node.queueChildren(queue, key);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
11
|
+
keys(prefix, includePrefix = true) {
|
|
12
|
+
return this.iterate((key) => key, prefix, includePrefix);
|
|
29
13
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
while (queue.length) {
|
|
33
|
-
const node = queue.pop();
|
|
34
|
-
if (node.val !== void 0) {
|
|
35
|
-
yield node.val;
|
|
36
|
-
} else {
|
|
37
|
-
queue.push(...Object.values(node.next));
|
|
38
|
-
}
|
|
39
|
-
}
|
|
14
|
+
values(prefix) {
|
|
15
|
+
return this.iterate((_, node) => node.val, prefix);
|
|
40
16
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
17
|
+
entries(prefix, includePrefix = true) {
|
|
18
|
+
return this.iterate(
|
|
19
|
+
(key, node) => [key, node.val],
|
|
20
|
+
prefix,
|
|
21
|
+
includePrefix
|
|
22
|
+
);
|
|
46
23
|
}
|
|
47
24
|
clear() {
|
|
48
25
|
this.next = {};
|
|
@@ -122,16 +99,38 @@ class TrieMap {
|
|
|
122
99
|
}
|
|
123
100
|
return true;
|
|
124
101
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
102
|
+
*iterate(fn, prefix = "", includePrefix = true) {
|
|
103
|
+
const root = this.find(prefix);
|
|
104
|
+
if (!root) return;
|
|
105
|
+
const queue = [
|
|
106
|
+
[includePrefix ? prefix : "", root]
|
|
107
|
+
];
|
|
108
|
+
while (queue.length) {
|
|
109
|
+
const [key, node] = queue.pop();
|
|
110
|
+
if (node.val !== void 0) yield fn(key, node);
|
|
111
|
+
queue.push(
|
|
112
|
+
...Object.entries(node.next).map(
|
|
113
|
+
([k, v]) => [key + k, v]
|
|
114
|
+
)
|
|
115
|
+
);
|
|
116
|
+
}
|
|
131
117
|
}
|
|
132
118
|
}
|
|
133
119
|
const defTrieMap = (pairs) => new TrieMap(pairs);
|
|
120
|
+
const defTrieMapFromJSON = (src) => {
|
|
121
|
+
const res = defTrieMap();
|
|
122
|
+
const queue = [["", src]];
|
|
123
|
+
while (queue.length) {
|
|
124
|
+
const [key, node] = queue.pop();
|
|
125
|
+
if (node.val) res.set(key, node.val);
|
|
126
|
+
for (let [k, child] of Object.entries(node.next)) {
|
|
127
|
+
queue.push([key + k, child]);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return res;
|
|
131
|
+
};
|
|
134
132
|
export {
|
|
135
133
|
TrieMap,
|
|
136
|
-
defTrieMap
|
|
134
|
+
defTrieMap,
|
|
135
|
+
defTrieMapFromJSON
|
|
137
136
|
};
|