semantic-typescript 0.5.3 → 0.6.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/dist/asynchronous/collector.d.ts +231 -0
- package/dist/asynchronous/collector.js +800 -0
- package/dist/asynchronous/semantic.d.ts +257 -0
- package/dist/asynchronous/semantic.js +1853 -0
- package/dist/factory.d.ts +71 -37
- package/dist/factory.js +443 -262
- package/dist/guard.d.ts +24 -14
- package/dist/guard.js +73 -19
- package/dist/hook.d.ts +6 -6
- package/dist/hook.js +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/optional.d.ts +2 -2
- package/dist/symbol.d.ts +19 -10
- package/dist/symbol.js +19 -10
- package/dist/synchronous/collector.d.ts +232 -0
- package/dist/{collector.js → synchronous/collector.js} +160 -151
- package/dist/{semantic.d.ts → synchronous/semantic.d.ts} +111 -120
- package/dist/{semantic.js → synchronous/semantic.js} +299 -337
- package/dist/utility.d.ts +7 -1
- package/dist/utility.js +1 -0
- package/package.json +1 -1
- package/readme.cn.md +158 -697
- package/readme.de.md +163 -432
- package/readme.es.md +163 -433
- package/readme.fr.md +162 -444
- package/readme.jp.md +162 -442
- package/readme.kr.md +161 -430
- package/readme.md +157 -1009
- package/readme.ru.md +161 -426
- package/readme.tw.md +161 -436
- package/dist/collector.d.ts +0 -236
- package/dist/main.d.ts +0 -1
- package/dist/main.js +0 -4
- package/dist/map.d.ts +0 -76
- package/dist/map.js +0 -245
- package/dist/node.d.ts +0 -182
- package/dist/node.js +0 -918
- package/dist/set.d.ts +0 -19
- package/dist/set.js +0 -65
- package/dist/tree.d.ts +0 -82
- package/dist/tree.js +0 -257
package/readme.tw.md
CHANGED
|
@@ -1,489 +1,214 @@
|
|
|
1
|
-
# Semantic-TypeScript
|
|
1
|
+
# Semantic-TypeScript:一款範式轉換的串流處理函式庫
|
|
2
2
|
|
|
3
3
|
## 簡介
|
|
4
|
+
Semantic-TypeScript 代表了串流處理技術的一項重大進步,它綜合了 JavaScript GeneratorFunctions、Java Streams 和資料庫索引範式中最有效的概念。其基礎設計原則的核心是透過複雜的惰性求值和智慧索引建構極其高效的資料處理管道。該函式庫提供了一個嚴格型別安全、函數式純正的串流式操作體驗,專門為現代 TypeScript 和 JavaScript 開發而設計。
|
|
4
5
|
|
|
5
|
-
Semantic-TypeScript
|
|
6
|
+
與傳統的同步處理架構相比,Semantic-TypeScript 實現了一個統一模型,優雅地處理同步(Iterable)和非同步(AsyncIterable)資料來源。在串流生成過程中,資料的流動和終止由回呼機制精確控制,使函式庫能夠以超凡的優雅處理:
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
- 具有確定性控制的即時資料流(DOM 事件、WebSockets、時間間隔)
|
|
9
|
+
- 透過記憶體高效的惰性管道處理大規模資料集
|
|
10
|
+
- 透過流暢、宣告式的 API 進行複雜的資料轉換
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
該函式庫的創新方法從根本上重新構想了開發者與資料序列互動的方式,在一個單一、內聚的套件中同時提供了前所未有的效能特性和開發者體驗。
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
+
## 核心理念:定義與執行的分離
|
|
15
|
+
Semantic-TypeScript 的一個關鍵架構洞見是清晰地分離串流的定義和執行:
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
| 類型 | 描述 |
|
|
18
|
-
|------|------|
|
|
19
|
-
| `Invalid<T>` | 擴展自 `null` 或 `undefined` 的類型 |
|
|
20
|
-
| `Valid<T>` | 排除 `null` 和 `undefined` 的類型 |
|
|
21
|
-
| `MaybeInvalid<T>` | 可能是 `null` 或 `undefined` 的類型 |
|
|
22
|
-
| `Primitive` | 原始類型的集合 |
|
|
23
|
-
| `MaybePrimitive<T>` | 可能是原始類型的類型 |
|
|
24
|
-
| `OptionalSymbol` | `Optional` 類的 Symbol 標識符 |
|
|
25
|
-
| `SemanticSymbol` | `Semantic` 類的 Symbol 標識符 |
|
|
26
|
-
| `CollectorsSymbol` | `Collector` 類的 Symbol 標識符 |
|
|
27
|
-
| `CollectableSymbol` | `Collectable` 類的 Symbol 標識符 |
|
|
28
|
-
| `OrderedCollectableSymbol` | `OrderedCollectable` 類的 Symbol 標識符 |
|
|
29
|
-
| `WindowCollectableSymbol` | `WindowCollectable` 類的 Symbol 標識符 |
|
|
30
|
-
| `StatisticsSymbol` | `Statistics` 類的 Symbol 標識符 |
|
|
31
|
-
| `NumericStatisticsSymbol` | `NumericStatistics` 類的 Symbol 標識符 |
|
|
32
|
-
| `BigIntStatisticsSymbol` | `BigIntStatistics` 類的 Symbol 標識符 |
|
|
33
|
-
| `UnorderedCollectableSymbol` | `UnorderedCollectable` 類的 Symbol 標識符 |
|
|
34
|
-
|
|
35
|
-
## 函數式接口
|
|
36
|
-
|
|
37
|
-
| 介面 | 描述 |
|
|
38
|
-
|------|------|
|
|
39
|
-
| `Runnable` | 無參數且無返回值的函數 |
|
|
40
|
-
| `Supplier<R>` | 無參數並返回 `R` 的函數 |
|
|
41
|
-
| `Functional<T, R>` | 單參數轉換函數 |
|
|
42
|
-
| `BiFunctional<T, U, R>` | 雙參數轉換函數 |
|
|
43
|
-
| `TriFunctional<T, U, V, R>` | 三參數轉換函數 |
|
|
44
|
-
| `Predicate<T>` | 單參數斷言函數 |
|
|
45
|
-
| `BiPredicate<T, U>` | 雙參數斷言函數 |
|
|
46
|
-
| `TriPredicate<T, U, V>` | 三參數斷言函數 |
|
|
47
|
-
| `Consumer<T>` | 單參數消費函數 |
|
|
48
|
-
| `BiConsumer<T, U>` | 雙參數消費函數 |
|
|
49
|
-
| `TriConsumer<T, U, V>` | 三參數消費函數 |
|
|
50
|
-
| `Comparator<T>` | 雙參數比較函數 |
|
|
51
|
-
| `Generator<T>` | 生成器函數(核心與基礎) |
|
|
17
|
+
- **Semantic<E>**:一個不可變的、惰性的資料轉換管道藍圖。它定義了將執行哪些操作(過濾、映射等)
|
|
18
|
+
- **Collectable<E>**:一個已實例化的、可執行的串流視圖。它是從 Semantic 獲取的,並提供所有終端操作(收集、遍歷等)來執行管道並產生結果
|
|
52
19
|
|
|
53
|
-
|
|
54
|
-
// 類型使用範例
|
|
55
|
-
let predicate: Predicate<number> = (n: number): boolean => n > 0;
|
|
56
|
-
let mapper: Functional<string, number> = (text: string): number => text.length;
|
|
57
|
-
let comparator: Comparator<number> = (a: number, b: number): number => a - b;
|
|
58
|
-
```
|
|
20
|
+
這種分離強化了清晰的心智模型,並釋放了強大的最佳化能力,例如選擇 UnorderedCollectable 來跳過不必要的排序以實現最大速度。
|
|
59
21
|
|
|
60
|
-
##
|
|
61
|
-
|
|
62
|
-
| 函數 | 描述 | 時間複雜度 | 空間複雜度 |
|
|
63
|
-
|------|------|------------|------------|
|
|
64
|
-
| `validate<T>(t: MaybeInvalid<T>): t is T` | 驗證值不是 null 或 undefined | O(1) | O(1) |
|
|
65
|
-
| `invalidate<T>(t: MaybeInvalid<T>): t is null \| undefined` | 驗證值是 null 或 undefined | O(1) | O(1) |
|
|
66
|
-
| `isBoolean(t: unknown): t is boolean` | 檢查是否為布林值 | O(1) | O(1) |
|
|
67
|
-
| `isString(t: unknown): t is string` | 檢查是否為字串 | O(1) | O(1) |
|
|
68
|
-
| `isNumber(t: unknown): t is number` | 檢查是否為數字 | O(1) | O(1) |
|
|
69
|
-
| `isFunction(t: unknown): t is Function` | 檢查是否為函數 | O(1) | O(1) |
|
|
70
|
-
| `isObject(t: unknown): t is object` | 檢查是否為物件 | O(1) | O(1) |
|
|
71
|
-
| `isSymbol(t: unknown): t is symbol` | 檢查是否為 Symbol | O(1) | O(1) |
|
|
72
|
-
| `isBigint(t: unknown): t is bigint` | 檢查是否為 BigInt | O(1) | O(1) |
|
|
73
|
-
| `isPrimitive(t: unknown): t is Primitive` | 檢查是否為原始類型 | O(1) | O(1) |
|
|
74
|
-
| `isIterable(t: unknown): t is Iterable<unknown>` | 檢查是否為可迭代物件 | O(1) | O(1) |
|
|
75
|
-
| `isOptional(t: unknown): t is Optional<unknown>` | 檢查是否為 Optional 實例 | O(1) | O(1) |
|
|
76
|
-
| `isSemantic(t: unknown): t is Semantic<unknown>` | 檢查是否為 Semantic 實例 | O(1) | O(1) |
|
|
77
|
-
| `isCollector(t: unknown): t is Collector<unknown, unknown, unknown>` | 檢查是否為 Collector 實例 | O(1) | O(1) |
|
|
78
|
-
| `isCollectable(t: unknown): t is Collectable<unknown>` | 檢查是否為 Collectable 實例 | O(1) | O(1) |
|
|
79
|
-
| `isOrderedCollectable(t: unknown): t is OrderedCollectable<unknown>` | 檢查是否為 OrderedCollectable 實例 | O(1) | O(1) |
|
|
80
|
-
| `isWindowCollectable(t: unknown): t is WindowCollectable<unknown>` | 檢查是否為 WindowCollectable 實例 | O(1) | O(1) |
|
|
81
|
-
| `isUnorderedCollectable(t: unknown): t is UnorderedCollectable<unknown>` | 檢查是否為 UnorderedCollectable 實例 | O(1) | O(1) |
|
|
82
|
-
| `isStatistics(t: unknown): t is Statistics<unknown, number \| bigint>` | 檢查是否為 Statistics 實例 | O(1) | O(1) |
|
|
83
|
-
| `isNumericStatistics(t: unknown): t is NumericStatistics<unknown>` | 檢查是否為 NumericStatistics 實例 | O(1) | O(1) |
|
|
84
|
-
| `isBigIntStatistics(t: unknown): t is BigIntStatistics<unknown>` | 檢查是否為 BigIntStatistics 實例 | O(1) | O(1) |
|
|
85
|
-
| `isPromise(t: unknown): t is Promise<unknown>` | 檢查是否為 Promise 物件 | O(1) | O(1) |
|
|
86
|
-
| `isAsync(t: unknown): t is AsyncFunction` | 檢查是否為 AsyncFunction | O(1) | O(1) |
|
|
22
|
+
## 為什麼選擇 Semantic-TypeScript?
|
|
23
|
+
為資料串流處理選擇合適的函式庫需要在效能、型別安全性和表達能力之間取得平衡。Semantic-TypeScript 的設計旨在所有這些維度上都表現出色。
|
|
87
24
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
let value: unknown = "hello";
|
|
25
|
+
### 1. 適用於所有資料序列的統一、型別安全範式
|
|
26
|
+
它為處理任何資料序列(無論是靜態陣列、即時事件還是非同步區塊)提供了一致的宣告式 API,同時利用 TypeScript 的全部功能確保端到端的型別安全。這消除了一整類執行時錯誤,並將串流操作轉變為可預測的、經過編譯器驗證的活動。
|
|
91
27
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
28
|
+
### 2. 以智慧惰性求值實現的不妥協效能
|
|
29
|
+
該函式庫的核心建立在惰性求值之上。諸如過濾器、映射和扁平映射等操作僅僅是組合一個處理管道;直到呼叫終端操作時,實際工作才會執行。這結合了短路功能(透過限制、任何匹配或自訂中斷回呼),允許處理提前停止,從而極大地提高了大型或無限串流的處理效率。
|
|
95
30
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
31
|
+
### 3. `Collector<E, A, R>` 模式的強大之處
|
|
32
|
+
受 Java 啟發,收集器模式是靈活性的引擎。它將如何累積串流元素的規範與串流本身的執行解耦。該函式庫為日常任務提供了一組豐富的內建收集器(toArray、groupBy、summate 等),同時使實現您自己複雜的、可重用的歸約邏輯變得非常簡單。這比固定的一組終端方法要強大和可組合得多。
|
|
99
33
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
for(let item of value){
|
|
103
|
-
console.log(item);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
```
|
|
34
|
+
### 4. 對現代 Web 和非同步資料的一流支援
|
|
35
|
+
Semantic-TypeScript 專為當代開發而設計。它為現代網路來源提供了原生工廠方法:
|
|
107
36
|
|
|
108
|
-
|
|
37
|
+
- `useFrom(iterable)`, `useRange()` 用於靜態資料
|
|
38
|
+
- `useInterval()`, `useAnimationFrame()` 用於基於時間的串流
|
|
39
|
+
- `useBlob()` 用於分塊二進位資料處理
|
|
40
|
+
- `useWebSocket()`, `useDocument()`, `useWindow()` 用於即時事件流
|
|
109
41
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
| `useCompare<T>(t1: T, t2: T): number` | 泛型比較函數 | O(1) | O(1) |
|
|
113
|
-
| `useRandom<T = number \| bigint>(index: T): T` | 偽隨機數產生器 | O(log n) | O(1) |
|
|
42
|
+
### 5. 超越基本聚合:內建統計分析
|
|
43
|
+
超越簡單的求和與平均。該函式庫提供了專用的 NumericStatistics 和 BigIntStatistics 介面,可以直接從您的串流中即時存取進階統計指標——變異數、標準差、中位數、偏度和峰度。這將複雜的資料分析變成了一行程式碼。
|
|
114
44
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
45
|
+
### 6. 為開發者體驗而設計
|
|
46
|
+
- **流暢、可鏈式呼叫的 API**:將複雜的資料管道編寫為可讀的、順序鏈
|
|
47
|
+
- **全面的工具套件**:包含必要的守衛(isFunction, isIterable)、實用程式(useCompare, useTraverse)和函數式介面
|
|
48
|
+
- **Optional<T> 整合**:安全地建模值的缺失,消除了空指標的擔憂
|
|
49
|
+
- **效能指南**:清楚地指導何時使用無序集合以獲得速度,何時使用有序集合以保持序列
|
|
119
50
|
|
|
120
|
-
|
|
51
|
+
## 安裝
|
|
52
|
+
```bash
|
|
53
|
+
npm install semantic-typescript
|
|
121
54
|
```
|
|
122
55
|
|
|
123
|
-
##
|
|
56
|
+
## 核心概念實踐
|
|
124
57
|
|
|
125
|
-
###
|
|
126
|
-
|
|
127
|
-
| 方法 | 描述 | 時間複雜度 | 空間複雜度 |
|
|
128
|
-
|------|------|------------|------------|
|
|
129
|
-
| `Optional.empty<T>()` | 建立一個空的 Optional | O(1) | O(1) |
|
|
130
|
-
| `Optional.of<T>(value)` | 建立一個包含值的 Optional | O(1) | O(1) |
|
|
131
|
-
| `Optional.ofNullable<T>(value)` | 建立一個可能為空的 Optional | O(1) | O(1) |
|
|
132
|
-
| `Optional.ofNonNull<T>(value)` | 建立一個非空的 Optional | O(1) | O(1) |
|
|
58
|
+
### 1. 建立串流 (Semantic)
|
|
59
|
+
可以使用工廠函數從各種來源建立串流。
|
|
133
60
|
|
|
134
61
|
```typescript
|
|
135
|
-
|
|
136
|
-
let empty: Optional<number> = Optional.empty();
|
|
137
|
-
let present: Optional<number> = Optional.of(42);
|
|
138
|
-
let nullable: Optional<string> = Optional.ofNullable<string>(null);
|
|
139
|
-
let nonNull: Optional<string> = Optional.ofNonNull("hello");
|
|
140
|
-
|
|
141
|
-
presentO.ifPresent((value: number): void => console.log(value)); // 輸出 42
|
|
142
|
-
console.log(empty.get(100)); // 輸出 100
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
### Collector 工廠方法
|
|
146
|
-
|
|
147
|
-
| 方法 | 描述 | 時間複雜度 | 空間複雜度 |
|
|
148
|
-
|------|------|------------|------------|
|
|
149
|
-
| `Collector.full(identity, accumulator, finisher)` | 建立一個完整的收集器 | O(1) | O(1) |
|
|
150
|
-
| `Collector.shortable(identity, interruptor, accumulator, finisher)` | 建立一個可中斷的收集器 | O(1) | O(1) |
|
|
62
|
+
import { useFrom, useInterval, useDocument } from 'semantic-typescript';
|
|
151
63
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
let numbers: Semantic<number> = from([3, 1, 4, 1, 5, 9, 2, 6, 5]);
|
|
155
|
-
|
|
156
|
-
// 效能優先:使用無序收集器
|
|
157
|
-
let unordered: UnorderedCollectable<number> = from([3, 1, 4, 1, 5, 9, 2, 6, 5])
|
|
158
|
-
.filter((n: number): boolean => n > 3)
|
|
159
|
-
.toUnordered();
|
|
160
|
-
|
|
161
|
-
// 需要排序:使用有序收集器
|
|
162
|
-
let ordered: OrderedCollectable<number> = from([3, 1, 4, 1, 5, 9, 2, 6, 5])
|
|
163
|
-
.sorted();
|
|
164
|
-
|
|
165
|
-
// 統計元素數量
|
|
166
|
-
let count: Collector<number, number, number> = Collector.full(
|
|
167
|
-
(): number => 0, // 初始值
|
|
168
|
-
(accumulator: number, element: number): number => accumulator + element, // 累積
|
|
169
|
-
(accumulator: number): number => accumulator // 完成
|
|
170
|
-
);
|
|
171
|
-
count.collect(from([1,2,3,4,5])); // 從流中統計
|
|
172
|
-
count.collect([1,2,3,4,5]); // 從可迭代物件統計
|
|
173
|
-
|
|
174
|
-
let find: Optional<number> = Collector.shortable(
|
|
175
|
-
(): Optional<number> => Optional.empty(), // 初始值
|
|
176
|
-
(element: number, index: bigint, accumulator: Optional<number>): Optional<number> => accumulator.isPresent(), // 中斷
|
|
177
|
-
(accumulator: Optional<number>, element: number, index: bigint): Optional<number> => Optional.of(element), // 累積
|
|
178
|
-
(accumulator: Optional<number>): Optional<number> => accumulator // 完成
|
|
179
|
-
);
|
|
180
|
-
find.collect(from([1,2,3,4,5])); // 查找第一個元素
|
|
181
|
-
find.collect([1,2,3,4,5]); // 查找第一個元素
|
|
182
|
-
```
|
|
64
|
+
// 從靜態陣列建立
|
|
65
|
+
const staticStream = useFrom([1, 2, 3, 4, 5]);
|
|
183
66
|
|
|
184
|
-
|
|
67
|
+
// 從非同步產生器建立
|
|
68
|
+
const asyncStream = useFrom(async function*() {
|
|
69
|
+
yield 1;
|
|
70
|
+
yield 2;
|
|
71
|
+
});
|
|
185
72
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
| `animationFrame(period: number, delay: number = 0)` | 建立定時動畫幀流 | O(1)* | O(1) |
|
|
189
|
-
| `blob(blob, chunkSize)` | 從 Blob 建立流 | O(n) | O(chunkSize) |
|
|
190
|
-
| `empty<E>()` | 建立空流 | O(1) | O(1) |
|
|
191
|
-
| `fill<E>(element, count)` | 建立填充流 | O(n) | O(1) |
|
|
192
|
-
| `from<E>(iterable)` | 從可迭代物件建立流 | O(1) | O(1) |
|
|
193
|
-
| `interval(period, delay?)` | 建立定時間隔流 | O(1)* | O(1) |
|
|
194
|
-
| `iterate<E>(generator)` | 從生成器建立流 | O(1) | O(1) |
|
|
195
|
-
| `range(start, end, step)` | 建立數值範圍流 | O(n) | O(1) |
|
|
196
|
-
| `websocket(websocket)` | 從 WebSocket 建立流 | O(1) | O(1) |
|
|
73
|
+
// 一個基於時間的串流
|
|
74
|
+
const tickStream = useInterval(1000); // 每秒發射一次
|
|
197
75
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
// 從定時動畫幀建立流
|
|
202
|
-
animationFrame(1000)
|
|
203
|
-
.toUnordered()
|
|
204
|
-
.forEach(frame => console.log(frame));
|
|
205
|
-
|
|
206
|
-
// 從 Blob 建立流(分塊讀取)
|
|
207
|
-
blob(someBlob, 1024n)
|
|
208
|
-
.toUnordered()
|
|
209
|
-
.write(WritableStream)
|
|
210
|
-
.then(callback) // 寫入流成功
|
|
211
|
-
.catch(callback); // 寫入流失敗
|
|
212
|
-
|
|
213
|
-
// 建立空流,需與其他流連接後才會執行
|
|
214
|
-
empty<string>()
|
|
215
|
-
.toUnordered()
|
|
216
|
-
.join(); //[]
|
|
217
|
-
|
|
218
|
-
// 建立填充流
|
|
219
|
-
let filledStream = fill("hello", 3); // "hello", "hello", "hello"
|
|
220
|
-
|
|
221
|
-
// 建立初始延遲 2 秒、執行週期 5 秒的定時流,基於定時器機制實現;可能因系統排程精確度限制產生時間漂移。
|
|
222
|
-
let intervalStream = interval(5000, 2000);
|
|
223
|
-
|
|
224
|
-
// 從可迭代物件建立流
|
|
225
|
-
let numberStream = from([1, 2, 3, 4, 5]);
|
|
226
|
-
let stringStream = from(new Set(["Alex", "Bob"]));
|
|
227
|
-
|
|
228
|
-
// 從已解析的 Promise 建立流
|
|
229
|
-
let promisedStream: Semantic<Array<number>> = Promise.resolve([1, 2, 3, 4, 5]);
|
|
230
|
-
|
|
231
|
-
// 建立範圍流
|
|
232
|
-
let rangeStream = range(1, 10, 2); // 1, 3, 5, 7, 9
|
|
233
|
-
|
|
234
|
-
// WebSocket 事件流
|
|
235
|
-
let ws = new WebSocket("ws://localhost:8080");
|
|
236
|
-
websocket(ws)
|
|
237
|
-
.filter((event): boolean => event.type === "message"); // 僅監聽訊息事件
|
|
238
|
-
.toUnordered() // 事件通常無序
|
|
239
|
-
.forEach((event): void => receive(event)); // 接收訊息
|
|
76
|
+
// 一個 DOM 事件流(參見下面的重要說明)
|
|
77
|
+
const clickStream = useDocument('click');
|
|
240
78
|
```
|
|
241
79
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
| 方法 | 描述 | 時間複雜度 | 空間複雜度 |
|
|
245
|
-
|------|------|------------|------------|
|
|
246
|
-
| `concat(other)` | 連接兩個流 | O(n) | O(1) |
|
|
247
|
-
| `distinct()` | 移除重複項 | O(n) | O(n) |
|
|
248
|
-
| `distinct(comparator)` | 使用比較器移除重複項 | O(n²) | O(n) |
|
|
249
|
-
| `dropWhile(predicate)` | 丟棄滿足條件的元素 | O(n) | O(1) |
|
|
250
|
-
| `filter(predicate)` | 過濾元素 | O(n) | O(1) |
|
|
251
|
-
| `flat(mapper)` | 平坦化映射 | O(n × m) | O(1) |
|
|
252
|
-
| `flatMap(mapper)` | 平坦化映射到新類型 | O(n × m) | O(1) |
|
|
253
|
-
| `limit(n)` | 限制元素數量 | O(n) | O(1) |
|
|
254
|
-
| `map(mapper)` | 映射轉換 | O(n) | O(1) |
|
|
255
|
-
| `peek(consumer)` | 查看元素 | O(n) | O(1) |
|
|
256
|
-
| `redirect(redirector)` | 重定向索引 | O(n) | O(1) |
|
|
257
|
-
| `reverse()` | 反轉流 | O(n) | O(1) |
|
|
258
|
-
| `shuffle()` | 隨機洗牌 | O(n) | O(1) |
|
|
259
|
-
| `shuffle(mapper)` | 使用映射器洗牌 | O(n) | O(1) |
|
|
260
|
-
| `skip(n)` | 跳過前 n 個元素 | O(n) | O(1) |
|
|
261
|
-
| `sorted()` | 排序 | O(n log n) | O(n) |
|
|
262
|
-
| `sorted(comparator)` | 使用比較器排序 | O(n log n) | O(n) |
|
|
263
|
-
| `sub(start, end)` | 取得子流 | O(n) | O(1) |
|
|
264
|
-
| `takeWhile(predicate)` | 取得滿足條件的元素 | O(n) | O(1) |
|
|
265
|
-
| `translate(offset)` | 平移索引 | O(n) | O(1) |
|
|
266
|
-
| `translate(translator)` | 使用翻譯器平移索引 | O(n) | O(1) |
|
|
80
|
+
### 2. 轉換串流(中間操作)
|
|
81
|
+
透過鏈式惰性呼叫來定義管道。
|
|
267
82
|
|
|
268
83
|
```typescript
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
.limit(3) // 限制為 3 個元素
|
|
275
|
-
.toUnordered() // 轉換為無序收集器
|
|
276
|
-
.toArray(); // 轉換為陣列
|
|
277
|
-
// 結果: [8, 12, 20]
|
|
278
|
-
|
|
279
|
-
// 複雜操作範例
|
|
280
|
-
let complexResult = range(1, 100, 1)
|
|
281
|
-
.flatMap((n: number): Semantics<number> => from([n, n * 2])) // 將每個元素映射為兩個
|
|
282
|
-
.distinct() // 移除重複項
|
|
283
|
-
.shuffle() // 隨機洗牌
|
|
284
|
-
.takeWhile((n: number): boolean => n < 50) // 取小於 50 的元素
|
|
285
|
-
.toOrdered() // 轉換為有序收集器
|
|
286
|
-
.toArray(); // 轉換為陣列
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
## Semantic 轉換方法
|
|
290
|
-
|
|
291
|
-
| 方法 | 描述 | 時間複雜度 | 空間複雜度 |
|
|
292
|
-
|------------|------------|------------|------------|
|
|
293
|
-
| `sorted()` | 轉換為有序收集器 | O(n log n) | O(n) |
|
|
294
|
-
| `toUnordered()` | 轉換為無序收集器 | O(1) | O(1) |
|
|
295
|
-
| `toOrdered()` | 轉換為有序收集器 | O(1) | O(1) |
|
|
296
|
-
| `toNumericStatistics()` | 轉換為數值統計 | O(n) | O(1) |
|
|
297
|
-
| `toBigintStatistics()` | 轉換為 BigInt 統計 | O(n) | O(1) |
|
|
298
|
-
| `toWindow()` | 轉換為視窗收集器 | O(1) | O(1) |
|
|
299
|
-
| `toCollectable()` | 轉換為 `UnorderdCollectable` | O(n) | O(1) |
|
|
300
|
-
| `toCollectable(mapper)` | 轉換為自訂收集器 | O(n) | O(1) |
|
|
84
|
+
const processedStream = staticStream
|
|
85
|
+
.filter(x => x % 2 === 0) // 僅保留偶數
|
|
86
|
+
.map(x => x * 10) // 乘以 10
|
|
87
|
+
.flatMap(x => [x, x + 1]) // 將每個元素轉換為兩個
|
|
88
|
+
.distinct(); // 移除重複項
|
|
301
89
|
|
|
302
|
-
|
|
303
|
-
// 轉換為升序陣列
|
|
304
|
-
from([6,4,3,5,2]) // 建立流
|
|
305
|
-
.sorted() // 按升序排序
|
|
306
|
-
.toArray(); // [2, 3, 4, 5, 6]
|
|
307
|
-
|
|
308
|
-
// 轉換為降序陣列
|
|
309
|
-
from([6,4,3,5,2]) // 建立流
|
|
310
|
-
.soted((a: number, b: number): number => b - a) // 按降序排序
|
|
311
|
-
.toArray(); // [6, 5, 4, 3, 2]
|
|
312
|
-
|
|
313
|
-
// 重定向為倒序陣列
|
|
314
|
-
from([6,4,3,5,2])
|
|
315
|
-
.redirect((element, index): bigint => -index) // 重定向為倒序
|
|
316
|
-
.toOrderd() // 保持重定向順序
|
|
317
|
-
.toArray(); // [2, 5, 3, 4, 6]
|
|
318
|
-
|
|
319
|
-
// 忽略重定向以倒序陣列
|
|
320
|
-
from([6,4,3,5,2])
|
|
321
|
-
.redirect((element: number, index: bigint) => -index) // 重定向為倒序
|
|
322
|
-
.toUnorderd() // 丟棄重定向順序。此操作將忽略 `redirect`、`reverse`、`shuffle` 和 `translate` 操作
|
|
323
|
-
.toArray(); // [2, 5, 3, 4, 6]
|
|
324
|
-
|
|
325
|
-
// 反轉流為陣列
|
|
326
|
-
from([6, 4, 3, 5, 2])
|
|
327
|
-
.reverse() // 反轉流
|
|
328
|
-
.toOrdered() // 保證反轉順序
|
|
329
|
-
.toArray(); // [2, 5, 3, 4, 6]
|
|
330
|
-
|
|
331
|
-
// 覆蓋洗牌的流為陣列
|
|
332
|
-
from([6, 4, 3, 5, 2])
|
|
333
|
-
.shuffle() // 洗牌流
|
|
334
|
-
.sorted() // 覆蓋洗牌順序。此操作將覆蓋 `redirect`、`reverse`、`shuffle` 和 `translate` 操作
|
|
335
|
-
.toArray(); // [2, 5, 3, 4, 6]
|
|
336
|
-
|
|
337
|
-
// 轉換為視窗收集器
|
|
338
|
-
from([6, 4, 3, 5, 2]).toWindow();
|
|
339
|
-
|
|
340
|
-
// 轉換為數值統計
|
|
341
|
-
from([6, 4, 3, 5, 2]).toNumericStatistics();
|
|
342
|
-
|
|
343
|
-
// 轉換為 BigInt 統計
|
|
344
|
-
from([6n, 4n, 3n, 5n, 2n]).toBigintStatistics();
|
|
345
|
-
|
|
346
|
-
// 定義自訂收集器來收集資料
|
|
347
|
-
let customizedCollector = from([1, 2, 3, 4, 5]).toCollectable((generator: Generator<E>) => new CustomizedCollector(generator));
|
|
90
|
+
// 此時尚未執行任何操作
|
|
348
91
|
```
|
|
349
92
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
| 方法 | 描述 | 時間複雜度 | 空間複雜度 |
|
|
353
|
-
|------|------|------------|------------|
|
|
354
|
-
| `anyMatch(predicate)` | 是否有任何元素符合 | O(n) | O(1) |
|
|
355
|
-
| `allMatch(predicate)` | 是否所有元素都符合 | O(n) | O(1) |
|
|
356
|
-
| `count()` | 元素計數 | O(n) | O(1) |
|
|
357
|
-
| `isEmpty()` | 是否為空 | O(1) | O(1) |
|
|
358
|
-
| `findAny()` | 查找任何元素 | O(n) | O(1) |
|
|
359
|
-
| `findFirst()` | 查找第一個元素 | O(n) | O(1) |
|
|
360
|
-
| `findLast()` | 查找最後一個元素 | O(n) | O(1) |
|
|
361
|
-
| `forEach(action)` | 遍歷所有元素 | O(n) | O(1) |
|
|
362
|
-
| `group(classifier)` | 按分類器分組 | O(n) | O(n) |
|
|
363
|
-
| `groupBy(keyExtractor, valueExtractor)` | 按鍵值提取器分組 | O(n) | O(n) |
|
|
364
|
-
| `join()` | 將元素連接為字串 | O(n) | O(n) |
|
|
365
|
-
| `join(delimiter)` | 使用分隔符連接元素 | O(n) | O(n) |
|
|
366
|
-
| `nonMatch(predicate)` | 是否沒有任何元素符合 | O(n) | O(1) |
|
|
367
|
-
| `partition(count)` | 按計數分區 | O(n) | O(n) |
|
|
368
|
-
| `partitionBy(classifier)` | 按分類器分區 | O(n) | O(n) |
|
|
369
|
-
| `reduce(accumulator)` | 歸約操作 | O(n) | O(1) |
|
|
370
|
-
| `reduce(identity, accumulator)` | 使用初始值的歸約操作 | O(n) | O(1) |
|
|
371
|
-
| `toArray()` | 轉換為陣列 | O(n) | O(n) |
|
|
372
|
-
| `toMap(keyExtractor, valueExtractor)` | 轉換為 Map | O(n) | O(n) |
|
|
373
|
-
| `toSet()` | 轉換為 Set | O(n) | O(n) |
|
|
374
|
-
| `write(stream)` | 寫入流 | O(n) | O(1) |
|
|
93
|
+
### 3. 執行串流(終端操作)
|
|
94
|
+
要獲得結果,必須取得一個 Collectable 並呼叫終端操作。
|
|
375
95
|
|
|
376
96
|
```typescript
|
|
377
|
-
//
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
console.log(
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
let grouped = data.groupBy(
|
|
392
|
-
(n: number): string => (n > 5 ? "large" : "small"),
|
|
393
|
-
(n: number): number => n * 2
|
|
394
|
-
); // {small: [4, 8], large: [12, 16, 20]}
|
|
395
|
-
|
|
396
|
-
// 歸約操作
|
|
397
|
-
let sum = data.reduce(0, (accumulator: number, n: number): number => accumulator + n); // 30
|
|
398
|
-
|
|
399
|
-
// 輸出操作
|
|
400
|
-
data.join(", "); // "[2, 4, 6, 8, 10]"
|
|
97
|
+
// 取得一個無序收集器以提高效能
|
|
98
|
+
const resultArray = await processedStream.toUnordered().toArray();
|
|
99
|
+
console.log(resultArray); // 例如:[20, 21, 40, 41]
|
|
100
|
+
|
|
101
|
+
// 使用內建收集器
|
|
102
|
+
const sum = await processedStream.toUnordered().collect(useSummate());
|
|
103
|
+
console.log(sum);
|
|
104
|
+
|
|
105
|
+
// 或使用通用的 collect 方法
|
|
106
|
+
const customResult = await processedStream.toOrdered().collect(
|
|
107
|
+
() => new Map<number, number>(),
|
|
108
|
+
(map, element, index) => map.set(index, element),
|
|
109
|
+
map => map
|
|
110
|
+
);
|
|
401
111
|
```
|
|
402
112
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
### NumericStatistics 方法
|
|
406
|
-
|
|
407
|
-
| 方法 | 描述 | 時間複雜度 | 空間複雜度 |
|
|
408
|
-
|------|------|------------|------------|
|
|
409
|
-
| `range()` | 範圍 | O(n) | O(1) |
|
|
410
|
-
| `variance()` | 變異數 | O(n) | O(1) |
|
|
411
|
-
| `standardDeviation()` | 標準差 | O(n) | O(1) |
|
|
412
|
-
| `mean()` | 平均 | O(n) | O(1) |
|
|
413
|
-
| `median()` | 中位數 | O(n log n) | O(n) |
|
|
414
|
-
| `mode()` | 眾數 | O(n) | O(n) |
|
|
415
|
-
| `frequency()` | 頻率分佈 | O(n) | O(n) |
|
|
416
|
-
| `summate()` | 總和 | O(n) | O(1) |
|
|
417
|
-
| `quantile(quantile)` | 分位數 | O(n log n) | O(n) |
|
|
418
|
-
| `interquartileRange()` | 四分位距 | O(n log n) | O(n) |
|
|
419
|
-
| `skewness()` | 偏態 | O(n) | O(1) |
|
|
420
|
-
| `kurtosis()` | 峰態 | O(n) | O(1) |
|
|
113
|
+
### 4. 關鍵:處理事件流
|
|
114
|
+
事件流(useDocument, useWindow, useHTMLElement, useWebSocket)本質上是無限的。您必須使用諸如 sub、takeWhile 或 limit 等操作來定義何時停止收集事件並完成串流。否則,終端操作將無限期等待。
|
|
421
115
|
|
|
422
116
|
```typescript
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
117
|
+
import { useDocument } from 'semantic-typescript';
|
|
118
|
+
|
|
119
|
+
// 僅收集前 5 次點擊
|
|
120
|
+
const first5Clicks = await useDocument('click')
|
|
121
|
+
.limit(5) // <- 關鍵:將串流限制為 5 個事件
|
|
122
|
+
.toUnordered()
|
|
123
|
+
.toArray();
|
|
124
|
+
|
|
125
|
+
// 收集 10 秒視窗內的點擊
|
|
126
|
+
const clicksIn10s = await useDocument('click')
|
|
127
|
+
.takeWhile((_, index, startTime = Date.now()) => Date.now() - startTime < 10000)
|
|
128
|
+
.toUnordered()
|
|
129
|
+
.toArray();
|
|
130
|
+
|
|
131
|
+
// 收集索引 2 到 5 的點擊(基於 0)
|
|
132
|
+
const specificClicks = await useDocument('click')
|
|
133
|
+
.sub(2n, 6n) // <- 獲取索引為 2, 3, 4, 5 的元素
|
|
134
|
+
.toUnordered()
|
|
135
|
+
.toArray();
|
|
439
136
|
```
|
|
440
137
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
### 選擇無序收集器(效能優先)
|
|
138
|
+
**關鍵見解**:事件(例如 MouseEvent)及其順序觸發索引(作為大整數)透過 `accept(event, index)` 回呼一起在管道中傳遞。
|
|
444
139
|
|
|
140
|
+
### 5. 利用統計功能
|
|
445
141
|
```typescript
|
|
446
|
-
|
|
447
|
-
let highPerformance = data
|
|
448
|
-
.filter(predicate)
|
|
449
|
-
.map(mapper)
|
|
450
|
-
.toUnordered(); // 最佳效能
|
|
451
|
-
```
|
|
142
|
+
const numericStream = useFrom([10, 20, 30, 40, 50]).toNumeric();
|
|
452
143
|
|
|
453
|
-
|
|
144
|
+
const average = await numericStream.average();
|
|
145
|
+
const median = await numericStream.median();
|
|
146
|
+
const standardDeviation = await numericStream.standardDeviation();
|
|
147
|
+
const skewness = await numericStream.skewness();
|
|
454
148
|
|
|
455
|
-
|
|
456
|
-
// 當需要維持元素順序時,使用有序收集器
|
|
457
|
-
let ordered = data.sorted(comparator);
|
|
149
|
+
console.log(`Average: ${average}, Median: ${median}, StdDev: ${standardDeviation}`);
|
|
458
150
|
```
|
|
459
151
|
|
|
460
|
-
|
|
461
|
-
|
|
152
|
+
## 主要特性
|
|
153
|
+
- **雙流類型**:完全支援同步語意(用於 Iterable)和非同步語意(用於 AsyncIterable 和事件)
|
|
154
|
+
- **豐富的操作集**:過濾器、映射、扁平映射、連接、去重、排序、限制、跳過、檢視、反轉、打亂
|
|
155
|
+
- **靈活的終端操作**:收集(使用自訂收集器)、toArray、toSet、toMap、forEach、reduce、findFirst、anyMatch、allMatch、count
|
|
156
|
+
- **進階收集器**:用於連接、分組、分割區、求和、平均、最大值、最小值的內建收集器
|
|
157
|
+
- **統計模組**:在數值/大整數流上用於均值、中位數、眾數、變異數、標準差、範圍、分位數、偏度、峰度的即用型方法
|
|
158
|
+
- **實用函數**:型別守衛(isPromise, isAsyncIterable)、比較器(useCompare)、遍歷(useTraverse)和轉換勾點
|
|
159
|
+
- **Optional<T>**:一個用於可空值的單子容器,與查詢操作整合
|
|
160
|
+
|
|
161
|
+
## API 概述
|
|
162
|
+
### 核心類別和介面
|
|
163
|
+
- `Semantic<E>` / `AsynchronousSemantic<E>`:抽象的串流定義
|
|
164
|
+
- `Collectable<E>` / `AsynchronousCollectable<E>`:具有終端操作的可執行串流
|
|
165
|
+
- `OrderedCollectable<E>` / `UnorderedCollectable<E>`:為順序敏感或順序不敏感操作最佳化的實例化版本
|
|
166
|
+
- `Collector<E, A, R>`:可變歸約操作的抽象
|
|
167
|
+
|
|
168
|
+
### 工廠函數 (use*)
|
|
169
|
+
- **從來源建立**:useFrom, useRange, useFill, useEmpty
|
|
170
|
+
- **從時間建立**:useInterval, useAnimationFrame
|
|
171
|
+
- **從 Web API 建立**:useBlob, useDocument, useWindow, useHTMLElement, useWebSocket
|
|
172
|
+
- **收集器**:useToArray, useGroupBy, useSummate, useJoin 等
|
|
173
|
+
|
|
174
|
+
## 效能說明
|
|
175
|
+
- **惰性求值**:在呼叫終端操作之前,管道僅組合而不執行
|
|
176
|
+
- **短路求值**:諸如限制、任何匹配和查詢首個等操作將在結果確定後立即停止處理元素
|
|
177
|
+
- **有序與無序**:
|
|
178
|
+
- 當來源元素的順序對您的結果不重要時(例如,求和、最大值或 toSet),對終端操作使用 `.toUnordered()`。這允許內部最佳化跳過昂貴的排序步驟
|
|
179
|
+
- 當順序很重要時(例如,toArray 必須保留順序),使用 `.toOrdered()`
|
|
180
|
+
|
|
181
|
+
## 入門範例
|
|
462
182
|
```typescript
|
|
463
|
-
|
|
464
|
-
let window: WindowCollectable<number> = data
|
|
465
|
-
.toWindow()
|
|
466
|
-
.slide(5n, 2n); // 滑動視窗
|
|
467
|
-
```
|
|
183
|
+
import { useFrom, useSummate, useGroupBy } from 'semantic-typescript';
|
|
468
184
|
|
|
469
|
-
|
|
185
|
+
interface Transaction {
|
|
186
|
+
id: number;
|
|
187
|
+
amount: number;
|
|
188
|
+
category: string;
|
|
189
|
+
}
|
|
470
190
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
191
|
+
const transactions: Transaction[] = [
|
|
192
|
+
{ id: 1, amount: 100, category: 'Food' },
|
|
193
|
+
{ id: 2, amount: 200, category: 'Electronics' },
|
|
194
|
+
{ id: 3, amount: 50, category: 'Food' },
|
|
195
|
+
{ id: 4, amount: 300, category: 'Electronics' },
|
|
196
|
+
];
|
|
197
|
+
|
|
198
|
+
// 計算每個類別的總金額
|
|
199
|
+
const totalsByCategory = await useFrom(transactions)
|
|
200
|
+
.toUnordered()
|
|
201
|
+
.collect(
|
|
202
|
+
useGroupBy(
|
|
203
|
+
t => t.category,
|
|
204
|
+
t => t.amount,
|
|
205
|
+
useSummate() // 值的收集器
|
|
206
|
+
)
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
console.log(totalsByCategory); // Map { 'Food' => 150, 'Electronics' => 500 }
|
|
477
210
|
```
|
|
478
211
|
|
|
479
|
-
|
|
480
|
-
[NPMJS](https://www.npmjs.com/package/semantic-typescript)
|
|
481
|
-
|
|
482
|
-
## 重要注意事項
|
|
483
|
-
|
|
484
|
-
1. **排序操作的影響**:在有序收集器中,`sorted()` 操作會覆蓋 `redirect`、`translate`、`shuffle`、`reverse` 的效果。
|
|
485
|
-
2. **效能考量**:如果不需要順序保證,優先使用 `toUnordered()` 以獲得更好的效能。
|
|
486
|
-
3. **記憶體使用**:排序操作需要額外的 O(n) 空間。
|
|
487
|
-
4. **即時資料**:Semantic 流適用於處理即時資料,並支援異步資料來源。
|
|
212
|
+
Semantic-TypeScript 是為那些尋求嚴格設計、型別安全和高效能串流處理函式庫的開發者而建構的。它將企業級資料轉換模式的力量帶入了 TypeScript 生態系統,非常適合資料密集型前端應用程式、Node.js 資料處理,以及任何需要優雅、高效處理序列的場景。
|
|
488
213
|
|
|
489
|
-
|
|
214
|
+
[](https://github.com/eloyhere/semantic-typescript) [](https://www.npmjs.com/package/semantic-typescript)
|