Powerful iterator utilities for ES2022+ with statistical operations, windowing, and lazy evaluation. Forward compatible with ES2025 iterator helpers.
- Why IterFlow?
- Features
- Installation
- Quick Start
- API Overview
- Statistical Operations
- Windowing Operations
- Grouping and Partitioning
- Set Operations
- Combining Iterators
- Interleaving Operations
- Utility Operations
- Generator Functions
- Advanced Examples
- TypeScript Support
- Performance
- Browser Support
IterFlow extends JavaScript's native iterators with powerful operations missing from the standard library:
- Statistical operations - Calculate mean, median, variance, percentiles directly on data streams
- Memory efficient - Process large datasets or infinite sequences without loading everything into memory
- Type-safe - Full TypeScript support with intelligent type inference throughout method chains
- Composable - Chain operations naturally with both wrapper and functional styles
- Future-proof - Designed to complement ES2025 iterator helpers, not replace them
Whether you're processing time-series data, analyzing datasets, or building data pipelines, IterFlow provides the missing pieces for elegant, efficient JavaScript.
- Lazy evaluation - Process infinite sequences efficiently
- Statistical operations - sum, mean, median, variance, percentile, and more
- Windowing - chunk, window, pairwise operations
- TypeScript-first - Perfect type inference throughout method chains
- Tree-shakeable - Import only what you need
- Zero dependencies - Pure JavaScript/TypeScript
- Dual API - Wrapper style + functional style
- Forward compatible - Works today, ready for ES2025 iterator helpers
npm install iterflowimport { iter } from 'iterflow';
// Statistical operations
const numbers = [1, 2, 3, 4, 5];
iter(numbers).sum(); // 15
iter(numbers).mean(); // 3
iter(numbers).median(); // 3
// Windowing operations
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) // [2, 4, 6]
.map(x => x * 2) // [4, 8, 12]
.chunk(2) // [[4, 8], [12]]
.toArray();import { iter } from 'iterflow';
const result = iter([1, 2, 3, 4, 5])
.filter(x => x > 2) // Native iterator method
.map(x => x * 2) // Native iterator method
.sum(); // IterFlow extension
console.log(result); // 18import { sum, filter, map, toArray } from 'iterflow/fn';
const data = [1, 2, 3, 4, 5];
const result = sum(map(x => x * 2)(filter(x => x > 2)(data)));
console.log(result); // 18All statistical operations work exclusively with numbers and include proper TypeScript constraints:
const numbers = iter([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
// Basic aggregates
numbers.sum(); // 55
numbers.mean(); // 5.5
numbers.min(); // 1
numbers.max(); // 10
numbers.count(); // 10
// Advanced statistics
numbers.median(); // 5.5
numbers.variance(); // 8.25
numbers.stdDev(); // ~2.87
numbers.percentile(75); // 7.75iter([]).sum(); // 0
iter([]).mean(); // undefined
iter([]).min(); // undefined
iter([]).max(); // undefinedCreates overlapping windows of a specified size:
iter([1, 2, 3, 4, 5])
.window(3)
.toArray();
// [[1,2,3], [2,3,4], [3,4,5]]Groups elements into non-overlapping chunks:
iter([1, 2, 3, 4, 5])
.chunk(2)
.toArray();
// [[1,2], [3,4], [5]]Creates pairs of consecutive elements (convenience for window(2)):
iter([1, 2, 3, 4])
.pairwise()
.toArray();
// [[1,2], [2,3], [3,4]]Splits an iterator into two arrays based on a predicate:
const [evens, odds] = iter([1, 2, 3, 4, 5, 6])
.partition(x => x % 2 === 0);
console.log(evens); // [2, 4, 6]
console.log(odds); // [1, 3, 5]Groups elements by a key function:
const items = [
{ category: 'fruit', name: 'apple' },
{ category: 'vegetable', name: 'carrot' },
{ category: 'fruit', name: 'banana' }
];
const groups = iter(items).groupBy(item => item.category);
// Map {
// 'fruit' => [{ category: 'fruit', name: 'apple' }, { category: 'fruit', name: 'banana' }],
// 'vegetable' => [{ category: 'vegetable', name: 'carrot' }]
// }Removes duplicates while preserving order:
iter([1, 2, 2, 3, 3, 3, 4])
.distinct()
.toArray();
// [1, 2, 3, 4]Removes duplicates based on a key function:
const people = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 1, name: 'Alice Jr' } // Different name, same id
];
iter(people)
.distinctBy(person => person.id)
.toArray();
// [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]Combines two iterators element by element:
iter.zip([1, 2, 3], ['a', 'b', 'c'])
.toArray();
// [[1,'a'], [2,'b'], [3,'c']]Combines two iterators using a custom function:
iter.zipWith([1, 2, 3], [4, 5, 6], (a, b) => a + b)
.toArray();
// [5, 7, 9]Alternates elements from multiple iterators in a round-robin fashion:
iter.interleave([1, 2, 3], [4, 5, 6])
.toArray();
// [1, 4, 2, 5, 3, 6]
iter.interleave([1, 2], [3, 4, 5], [6])
.toArray();
// [1, 3, 6, 2, 4, 5]Merges multiple sorted iterators while maintaining sort order:
iter.merge([1, 3, 5], [2, 4, 6])
.toArray();
// [1, 2, 3, 4, 5, 6]
// With custom comparator for descending order
iter.merge((a, b) => b - a, [9, 5, 1], [10, 6, 2])
.toArray();
// [10, 9, 6, 5, 2, 1]Chains multiple iterators sequentially, one after another:
iter.chain([1, 2], [3, 4], [5, 6])
.toArray();
// [1, 2, 3, 4, 5, 6]Executes a function for each element without modifying the stream:
iter([1, 2, 3])
.tap(x => console.log(`Processing: ${x}`))
.map(x => x * 2)
.toArray();
// Logs: Processing: 1, Processing: 2, Processing: 3
// Returns: [2, 4, 6]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]Creates numeric sequences:
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]Repeats a value:
iter.repeat('hello', 3).toArray(); // ['hello', 'hello', 'hello']
iter.repeat(0).take(5).toArray(); // [0, 0, 0, 0, 0] (infinite)interface Sale {
product: string;
amount: number;
category: string;
date: string;
}
const sales: Sale[] = [
{ product: 'Laptop', amount: 1200, category: 'Electronics', date: '2024-01' },
{ product: 'Mouse', amount: 25, category: 'Electronics', date: '2024-01' },
{ product: 'Book', amount: 15, category: 'Books', date: '2024-01' },
// ... more data
];
// Calculate average electronics sale amount
const electronicsAverage = iter(sales)
.filter(sale => sale.category === 'Electronics')
.map(sale => sale.amount)
.mean();
// Group by category and get total sales in each
const salesByCategory = iter(sales)
.groupBy(sale => sale.category)
.entries()
.map(([category, sales]) => ({
category,
total: iter(sales)
.map(sale => sale.amount)
.sum()
}));// Fibonacci sequence
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();
console.log(evenFibs); // [0, 2, 8, 34, 144, 610, 2584, 10946, 46368, 196418]const temperatures = [20, 22, 25, 23, 21, 19, 18, 20, 22, 24, 26, 25];
// Calculate 3-day moving averages
const movingAverages = iter(temperatures)
.window(3)
.map(window => iter(window).mean())
.toArray();
// Find periods of increasing temperature
const increasingPeriods = iter(temperatures)
.pairwise()
.map(([prev, curr], index) => ({ index: index + 1, increase: curr > prev }))
.filter(({ increase }) => increase)
.toArray();IterFlow is built with TypeScript-first design and provides excellent type inference:
// Type is automatically inferred as IterFlow<string>
const strings = iter(['hello', 'world'])
.map(s => s.toUpperCase())
.filter(s => s.length > 4);
// Statistical operations are constrained to numbers
const numbers = iter([1, 2, 3]);
numbers.sum(); // ✓ Works
strings.sum(); // ✗ TypeScript error
// Complex type transformations are preserved
interface Person {
name: string;
age: number;
}
const adults = iter([
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 17 },
{ name: 'Charlie', age: 30 }
])
.filter(person => person.age >= 18) // Still IterFlow<Person>
.distinctBy(person => person.name); // Still IterFlow<Person>IterFlow uses lazy evaluation, meaning operations are only computed when needed:
const expensiveOperation = iter(largeArray)
.map(heavyComputation) // Not computed yet
.filter(complexPredicate) // Not computed yet
.take(5); // Still not computed
const results = expensiveOperation.toArray(); // Now computed, only for first 5 matchesThis makes it efficient for processing large datasets or infinite sequences.
When IterFlow excels:
- Early termination: Operations like
find(),some(),take()benefit from lazy evaluation - Large pipelines: Multiple transformations on large datasets with minimal memory overhead
- Windowing operations: Memory-efficient sliding windows and chunking
- Generator integration: Working with infinite or very large sequences
- Statistical operations: Built-in optimized implementations for
mean(),median(),variance(), etc.
When native arrays may be faster:
- Small arrays (< 1000 items) where native method overhead is minimal
- Full materialization scenarios where all results are needed
- Single operations on entire arrays
We maintain a comprehensive benchmark suite comparing IterFlow against native array methods, Lodash, and Ramda:
# Run all benchmarks
npm run bench
# Run specific benchmark categories
npm run bench:transformations # Map, filter, take, etc.
npm run bench:terminals # Reduce, find, some, every
npm run bench:statistics # Sum, mean, median, variance
npm run bench:windowing # Chunk, window, partition
npm run bench:lazy # Lazy evaluation benefits
npm run bench:memory # Memory efficiency profilingFor detailed benchmark results and methodology, see docs/testing/BENCHMARKS.md.
Performance benchmarks run automatically in CI on every pull request and push to main.
IterFlow requires ES2022+ features including iterators, generators, Map, and Set. For older browser support, use a transpiler like TypeScript or Babel.
When ES2025 iterator helpers become available natively, IterFlow will work alongside them seamlessly as it's designed to extend rather than replace the native functionality.
We welcome contributions! Please see our contributing guidelines for details.
MIT
- Initial release
- Complete statistical operations suite
- Windowing and grouping operations
- TypeScript type constraints
- Dual API support (wrapper + functional)
- Comprehensive test coverage