Iterator utilities for ES2022+ with statistical operations, windowing, and lazy evaluation.
npm install iterflowimport { iter } from 'iterflow';
// Statistical operations
iter([1, 2, 3, 4, 5]).mean(); // 3
iter([1, 2, 3, 4, 5]).median(); // 3
// Windowing
iter([1, 2, 3, 4, 5])
.window(2)
.toArray();
// [[1,2], [2,3], [3,4], [4,5]]
// Method chaining
iter([1, 2, 3, 4, 5, 6])
.filter(x => x % 2 === 0)
.map(x => x * 2)
.chunk(2)
.toArray();
// [[4, 8], [12]]New in v0.8.0: Production-ready safety features to protect against infinite loops, slow operations, and runaway resource usage:
// Prevent infinite loops with hard limits
iter.range(Infinity)
.limit(10000) // Throws if exceeded
.toArray(1000); // Collects max 1000 items
// Timeout async operations
await asyncIter(items)
.map(slowOperation)
.timeout(5000) // 5s per iteration
.toArray();
// User cancellation with AbortController
const controller = new AbortController();
const promise = asyncIter(largeJob)
.withSignal(controller.signal)
.toArray();
// User clicks cancel
controller.abort('User cancelled');New APIs:
limit(maxIterations)- Throw OperationError if iteration limit exceededtimeout(ms)- Throw TimeoutError if async operations are too slowwithSignal(signal)- Integrate with AbortController for cancellationtoArray(maxSize?)- Optional size limit for safe collection- New error types:
TimeoutError,AbortError
For complete details, see the Resource Limits Guide.
import { iter } from 'iterflow';
iter([1, 2, 3, 4, 5])
.filter(x => x > 2) // Native iterator method
.map(x => x * 2) // Native iterator method
.sum(); // iterflow extension - 24import { sum, filter, map } from 'iterflow/fn';
const data = [1, 2, 3, 4, 5];
sum(map(x => x * 2)(filter(x => x > 2)(data))); // 24iter([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).sum(); // 55
iter([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).mean(); // 5.5
iter([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).median(); // 5.5
iter([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).variance(); // 8.25
iter([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).percentile(75); // 7.75// Sliding window
iter([1, 2, 3, 4, 5]).window(3).toArray();
// [[1,2,3], [2,3,4], [3,4,5]]
// Non-overlapping chunks
iter([1, 2, 3, 4, 5]).chunk(2).toArray();
// [[1,2], [3,4], [5]]
// Consecutive pairs
iter([1, 2, 3, 4]).pairwise().toArray();
// [[1,2], [2,3], [3,4]]// Partition by predicate
const [evens, odds] = iter([1, 2, 3, 4, 5, 6])
.partition(x => x % 2 === 0);
// Group by key function
const items = [
{ category: 'fruit', name: 'apple' },
{ category: 'vegetable', name: 'carrot' },
{ category: 'fruit', name: 'banana' }
];
const groups = iter(items).groupBy(item => item.category);// Remove duplicates
iter([1, 2, 2, 3, 3, 3, 4]).distinct().toArray();
// [1, 2, 3, 4]
// Remove duplicates by key
iter(people).distinctBy(person => person.id).toArray();// Zip iterators
iter.zip([1, 2, 3], ['a', 'b', 'c']).toArray();
// [[1,'a'], [2,'b'], [3,'c']]
// Interleave round-robin
iter.interleave([1, 2, 3], [4, 5, 6]).toArray();
// [1, 4, 2, 5, 3, 6]
// Merge sorted iterators
iter.merge([1, 3, 5], [2, 4, 6]).toArray();
// [1, 2, 3, 4, 5, 6]// Side effects
iter([1, 2, 3])
.tap(x => console.log(`Processing: ${x}`))
.map(x => x * 2)
.toArray();
// Conditional take/drop
iter([1, 2, 3, 4, 3, 2, 1]).takeWhile(x => x < 4).toArray();
// [1, 2, 3]
iter([1, 2, 3, 4, 5]).dropWhile(x => x < 3).toArray();
// [3, 4, 5]// Numeric ranges
iter.range(5).toArray(); // [0, 1, 2, 3, 4]
iter.range(2, 8).toArray(); // [2, 3, 4, 5, 6, 7]
iter.range(0, 10, 2).toArray(); // [0, 2, 4, 6, 8]
// Repeat values
iter.repeat('hello', 3).toArray(); // ['hello', 'hello', 'hello']
iter.repeat(0).take(5).toArray(); // [0, 0, 0, 0, 0]interface Sale {
product: string;
amount: number;
category: string;
}
const sales: Sale[] = [
{ product: 'Laptop', amount: 1200, category: 'Electronics' },
{ product: 'Mouse', amount: 25, category: 'Electronics' },
{ product: 'Book', amount: 15, category: 'Books' },
];
// Average electronics sale amount
const electronicsAvg = iter(sales)
.filter(sale => sale.category === 'Electronics')
.map(sale => sale.amount)
.mean();
// Total sales by category
const salesByCategory = iter(sales)
.groupBy(sale => sale.category)
.entries()
.map(([category, sales]) => ({
category,
total: iter(sales).map(sale => sale.amount).sum()
}));function* fibonacci() {
let a = 0, b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
// First 10 even fibonacci numbers
const evenFibs = iter(fibonacci())
.filter(x => x % 2 === 0)
.take(10)
.toArray();const temperatures = [20, 22, 25, 23, 21, 19, 18, 20, 22, 24];
const movingAverages = iter(temperatures)
.window(3)
.map(window => iter(window).mean())
.toArray();iterflow balances developer experience with performance. Here's how to decide:
- Large datasets (1000+ items) - lazy evaluation avoids unnecessary work
- Early termination - finding first match, taking limited results (find, some, every, take)
- Memory efficiency - windowing, chunking, or processing huge files
- Complex pipelines - chaining 3+ operations together
- Statistical operations - mean, median, variance, percentile calculations
- Code readability - method chaining feels more natural than manual loops
- Small arrays (< 100 items) - native Array methods are slightly faster
- Single simple operation - map or filter alone on small data
- Performance-critical hot paths - called millions of times, every microsecond matters
- Need multiple iterations - arrays are easier to loop over multiple times
iterflow uses lazy evaluation, which means:
- Lower memory usage - no intermediate arrays created
- Slightly slower per operation - small function call overhead
- Better for large datasets - memory savings far exceed speed cost
- Better for partial consumption - stops early when possible
For datasets < 100 items, the differences are negligible—use what feels natural.
For datasets > 1000 items:
- With early termination (take 10 from 100K): iterflow can be 20-300x faster
- With windowing (moving average): iterflow can be 35-600x faster due to memory efficiency
- Full consumption (process all items): native arrays are 2-5x faster
See docs/BENCHMARKS.md for detailed performance data and specific operation comparisons.
- FAQ - Frequently asked questions, common patterns, and troubleshooting
- Examples - Real-world usage examples
- Memory Safety Guide - Avoiding memory leaks and efficient memory usage
- Performance Guide - Optimization techniques and benchmarking
- Benchmarking Guide - Running and interpreting benchmarks
- SECURITY.md - Security best practices and vulnerability reporting
We welcome contributions! Please see our PLAYBOOK.md for:
- Development workflow and branching strategy
- Commit message guidelines
- Testing requirements
- Release process
For quick start:
- Fork the repository
- Create a feature branch from
dev - Make your changes with tests
- Submit a PR to
dev
See PLAYBOOK.md for complete details.
The Unlicense - See LICENSE for details.