iterflow 0.4.0 → 0.7.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/README.md +41 -2
- package/dist/fn/index.cjs +48 -22
- package/dist/fn/index.cjs.map +1 -1
- package/dist/fn/index.js +48 -22
- package/dist/fn/index.js.map +1 -1
- package/dist/index.cjs +86 -115
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -136
- package/dist/index.d.ts +2 -136
- package/dist/index.js +87 -109
- package/dist/index.js.map +1 -1
- package/package.json +20 -2
package/README.md
CHANGED
|
@@ -221,13 +221,52 @@ const movingAverages = iter(temperatures)
|
|
|
221
221
|
.toArray();
|
|
222
222
|
```
|
|
223
223
|
|
|
224
|
-
|
|
225
|
-
|
|
224
|
+
## When to Use iterflow
|
|
225
|
+
|
|
226
|
+
iterflow balances developer experience with performance. Here's how to decide:
|
|
227
|
+
|
|
228
|
+
### Use iterflow when:
|
|
229
|
+
|
|
230
|
+
- **Large datasets** (1000+ items) - lazy evaluation avoids unnecessary work
|
|
231
|
+
- **Early termination** - finding first match, taking limited results (find, some, every, take)
|
|
232
|
+
- **Memory efficiency** - windowing, chunking, or processing huge files
|
|
233
|
+
- **Complex pipelines** - chaining 3+ operations together
|
|
234
|
+
- **Statistical operations** - mean, median, variance, percentile calculations
|
|
235
|
+
- **Code readability** - method chaining feels more natural than manual loops
|
|
236
|
+
|
|
237
|
+
### Consider alternatives when:
|
|
238
|
+
|
|
239
|
+
- **Small arrays** (< 100 items) - native Array methods are slightly faster
|
|
240
|
+
- **Single simple operation** - map or filter alone on small data
|
|
241
|
+
- **Performance-critical hot paths** - called millions of times, every microsecond matters
|
|
242
|
+
- **Need multiple iterations** - arrays are easier to loop over multiple times
|
|
243
|
+
|
|
244
|
+
### The Trade-off
|
|
245
|
+
|
|
246
|
+
iterflow uses lazy evaluation, which means:
|
|
247
|
+
- **Lower memory usage** - no intermediate arrays created
|
|
248
|
+
- **Slightly slower per operation** - small function call overhead
|
|
249
|
+
- **Better for large datasets** - memory savings far exceed speed cost
|
|
250
|
+
- **Better for partial consumption** - stops early when possible
|
|
251
|
+
|
|
252
|
+
### Real Performance Impact
|
|
253
|
+
|
|
254
|
+
For datasets < 100 items, the differences are negligible—use what feels natural.
|
|
255
|
+
|
|
256
|
+
For datasets > 1000 items:
|
|
257
|
+
- **With early termination** (take 10 from 100K): iterflow can be 20-300x faster
|
|
258
|
+
- **With windowing** (moving average): iterflow can be 35-600x faster due to memory efficiency
|
|
259
|
+
- **Full consumption** (process all items): native arrays are 2-5x faster
|
|
260
|
+
|
|
261
|
+
See **[docs/BENCHMARKS.md](docs/BENCHMARKS.md)** for detailed performance data and specific operation comparisons.
|
|
226
262
|
|
|
227
263
|
## Documentation
|
|
228
264
|
|
|
229
265
|
- **[FAQ](FAQ.md)** - Frequently asked questions, common patterns, and troubleshooting
|
|
230
266
|
- **[Examples](examples/)** - Real-world usage examples
|
|
267
|
+
- **[Memory Safety Guide](docs/guides/memory-safety.md)** - Avoiding memory leaks and efficient memory usage
|
|
268
|
+
- **[Performance Guide](docs/PERFORMANCE.md)** - Optimization techniques and benchmarking
|
|
269
|
+
- **[Benchmarking Guide](docs/BENCHMARKING.md)** - Running and interpreting benchmarks
|
|
231
270
|
- **[SECURITY.md](SECURITY.md)** - Security best practices and vulnerability reporting
|
|
232
271
|
|
|
233
272
|
## Contributing
|
package/dist/fn/index.cjs
CHANGED
|
@@ -183,6 +183,13 @@ function transducerToIterator(transducer) {
|
|
|
183
183
|
|
|
184
184
|
// src/fn/index.ts
|
|
185
185
|
function sum(iterable) {
|
|
186
|
+
if (Array.isArray(iterable)) {
|
|
187
|
+
let total2 = 0;
|
|
188
|
+
for (let i = 0; i < iterable.length; i++) {
|
|
189
|
+
total2 += iterable[i];
|
|
190
|
+
}
|
|
191
|
+
return total2;
|
|
192
|
+
}
|
|
186
193
|
let total = 0;
|
|
187
194
|
for (const value of iterable) {
|
|
188
195
|
total += value;
|
|
@@ -190,6 +197,14 @@ function sum(iterable) {
|
|
|
190
197
|
return total;
|
|
191
198
|
}
|
|
192
199
|
function mean(iterable) {
|
|
200
|
+
if (Array.isArray(iterable)) {
|
|
201
|
+
if (iterable.length === 0) return void 0;
|
|
202
|
+
let total2 = 0;
|
|
203
|
+
for (let i = 0; i < iterable.length; i++) {
|
|
204
|
+
total2 += iterable[i];
|
|
205
|
+
}
|
|
206
|
+
return total2 / iterable.length;
|
|
207
|
+
}
|
|
193
208
|
let total = 0;
|
|
194
209
|
let count2 = 0;
|
|
195
210
|
for (const value of iterable) {
|
|
@@ -199,6 +214,10 @@ function mean(iterable) {
|
|
|
199
214
|
return count2 === 0 ? void 0 : total / count2;
|
|
200
215
|
}
|
|
201
216
|
function min(iterable) {
|
|
217
|
+
if (Array.isArray(iterable)) {
|
|
218
|
+
if (iterable.length === 0) return void 0;
|
|
219
|
+
return Math.min(...iterable);
|
|
220
|
+
}
|
|
202
221
|
let minimum = void 0;
|
|
203
222
|
for (const value of iterable) {
|
|
204
223
|
if (minimum === void 0 || value < minimum) {
|
|
@@ -208,6 +227,10 @@ function min(iterable) {
|
|
|
208
227
|
return minimum;
|
|
209
228
|
}
|
|
210
229
|
function max(iterable) {
|
|
230
|
+
if (Array.isArray(iterable)) {
|
|
231
|
+
if (iterable.length === 0) return void 0;
|
|
232
|
+
return Math.max(...iterable);
|
|
233
|
+
}
|
|
211
234
|
let maximum = void 0;
|
|
212
235
|
for (const value of iterable) {
|
|
213
236
|
if (maximum === void 0 || value > maximum) {
|
|
@@ -217,6 +240,9 @@ function max(iterable) {
|
|
|
217
240
|
return maximum;
|
|
218
241
|
}
|
|
219
242
|
function count(iterable) {
|
|
243
|
+
if (Array.isArray(iterable)) {
|
|
244
|
+
return iterable.length;
|
|
245
|
+
}
|
|
220
246
|
let count2 = 0;
|
|
221
247
|
for (const _ of iterable) {
|
|
222
248
|
count2++;
|
|
@@ -224,18 +250,18 @@ function count(iterable) {
|
|
|
224
250
|
return count2;
|
|
225
251
|
}
|
|
226
252
|
function median(iterable) {
|
|
227
|
-
const values = Array.from(iterable);
|
|
253
|
+
const values = Array.isArray(iterable) ? iterable : Array.from(iterable);
|
|
228
254
|
if (values.length === 0) return void 0;
|
|
229
|
-
values.sort((a, b) => a - b);
|
|
230
|
-
const mid = Math.floor(
|
|
231
|
-
if (
|
|
232
|
-
return (
|
|
255
|
+
const sorted = values.slice().sort((a, b) => a - b);
|
|
256
|
+
const mid = Math.floor(sorted.length / 2);
|
|
257
|
+
if (sorted.length % 2 === 0) {
|
|
258
|
+
return (sorted[mid - 1] + sorted[mid]) / 2;
|
|
233
259
|
} else {
|
|
234
|
-
return
|
|
260
|
+
return sorted[mid];
|
|
235
261
|
}
|
|
236
262
|
}
|
|
237
263
|
function variance(iterable) {
|
|
238
|
-
const values = Array.from(iterable);
|
|
264
|
+
const values = Array.isArray(iterable) ? iterable : Array.from(iterable);
|
|
239
265
|
if (values.length === 0) return void 0;
|
|
240
266
|
const mean2 = values.reduce((sum2, val) => sum2 + val, 0) / values.length;
|
|
241
267
|
let sumSquaredDiffs = 0;
|
|
@@ -251,22 +277,22 @@ function stdDev(iterable) {
|
|
|
251
277
|
}
|
|
252
278
|
function percentile(iterable, p) {
|
|
253
279
|
validateRange(p, 0, 100, "percentile", "percentile");
|
|
254
|
-
const values = Array.from(iterable);
|
|
280
|
+
const values = Array.isArray(iterable) ? iterable : Array.from(iterable);
|
|
255
281
|
if (values.length === 0) return void 0;
|
|
256
|
-
values.sort((a, b) => a - b);
|
|
257
|
-
if (p === 0) return
|
|
258
|
-
if (p === 100) return
|
|
259
|
-
const index = p / 100 * (
|
|
282
|
+
const sorted = values.slice().sort((a, b) => a - b);
|
|
283
|
+
if (p === 0) return sorted[0];
|
|
284
|
+
if (p === 100) return sorted[sorted.length - 1];
|
|
285
|
+
const index = p / 100 * (sorted.length - 1);
|
|
260
286
|
const lower = Math.floor(index);
|
|
261
287
|
const upper = Math.ceil(index);
|
|
262
288
|
if (lower === upper) {
|
|
263
|
-
return
|
|
289
|
+
return sorted[lower];
|
|
264
290
|
}
|
|
265
291
|
const weight = index - lower;
|
|
266
|
-
return
|
|
292
|
+
return sorted[lower] * (1 - weight) + sorted[upper] * weight;
|
|
267
293
|
}
|
|
268
294
|
function mode(iterable) {
|
|
269
|
-
const values = Array.from(iterable);
|
|
295
|
+
const values = Array.isArray(iterable) ? iterable : Array.from(iterable);
|
|
270
296
|
if (values.length === 0) return void 0;
|
|
271
297
|
const frequency = /* @__PURE__ */ new Map();
|
|
272
298
|
let maxFreq = 0;
|
|
@@ -284,20 +310,20 @@ function mode(iterable) {
|
|
|
284
310
|
return modes.sort((a, b) => a - b);
|
|
285
311
|
}
|
|
286
312
|
function quartiles(iterable) {
|
|
287
|
-
const values = Array.from(iterable);
|
|
313
|
+
const values = Array.isArray(iterable) ? iterable : Array.from(iterable);
|
|
288
314
|
if (values.length === 0) return void 0;
|
|
289
|
-
values.sort((a, b) => a - b);
|
|
315
|
+
const sorted = values.slice().sort((a, b) => a - b);
|
|
290
316
|
const calculatePercentile = (p) => {
|
|
291
|
-
if (p === 0) return
|
|
292
|
-
if (p === 100) return
|
|
293
|
-
const index = p / 100 * (
|
|
317
|
+
if (p === 0) return sorted[0];
|
|
318
|
+
if (p === 100) return sorted[sorted.length - 1];
|
|
319
|
+
const index = p / 100 * (sorted.length - 1);
|
|
294
320
|
const lower = Math.floor(index);
|
|
295
321
|
const upper = Math.ceil(index);
|
|
296
322
|
if (lower === upper) {
|
|
297
|
-
return
|
|
323
|
+
return sorted[lower];
|
|
298
324
|
}
|
|
299
325
|
const weight = index - lower;
|
|
300
|
-
return
|
|
326
|
+
return sorted[lower] * (1 - weight) + sorted[upper] * weight;
|
|
301
327
|
};
|
|
302
328
|
return {
|
|
303
329
|
Q1: calculatePercentile(25),
|