@chaisser/chunk-array
v1.0.1
Published
Split arrays into chunks
Maintainers
Readme
✂️ @chaisser/chunk-array
Split arrays into chunks — basic, balanced, overlapping, exact, lazy, async, and more
✨ Features
- 🎯 Type-safe - Full TypeScript support with generics
- ✂️ Basic chunking - Split arrays by size
- ⚖️ Balanced - Split into N equal chunks
- 🔁 Overlapping - Sliding window chunks
- 📐 Exact size - Pad or trim to exact chunk sizes
- 🔍 First / Last - Get only the first or last chunk
- 🏷️ Chunk by predicate - Split based on custom logic
- 🔁 Lazy iterator - Iterate chunks on demand
- ⚙️ Processor class - Process chunks incrementally
- 📊 Progress tracking - Chunk with progress callbacks
- 🔄 Async processing - Process chunks sequentially with async functions
- 🪶 Zero dependencies - Lightweight and tree-shakeable
- 🏎️ ESM + CJS - Dual module format support
📦 Installation
npm install @chaisser/chunk-array
# or
yarn add @chaisser/chunk-array
# or
pnpm add @chaisser/chunk-array🚀 Quick Start
import {
chunk,
chunkInto,
chunkBalanced,
chunkOverlapping,
chunkBy,
LazyChunkIterator,
} from '@chaisser/chunk-array';
// Basic chunking
chunk([1, 2, 3, 4, 5], 2);
// [[1, 2], [3, 4], [5]]
// Split into N chunks
chunkInto([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3);
// [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
// Balanced chunks (equal distribution)
chunkBalanced([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 3);
// [[1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
// Overlapping (sliding window)
chunkOverlapping([1, 2, 3, 4, 5], 3, 1);
// [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
// Chunk by predicate
chunkBy([1, 'a', 2, 'b', 3], (_, i) => i % 2 === 1);
// [[1], [2], [3]]📖 What It Does
This package provides a comprehensive set of array chunking utilities for JavaScript and TypeScript. It handles basic splitting, balanced distribution, overlapping windows, exact-size padding, lazy iteration, predicate-based splitting, and async processing — all with full TypeScript generics.
🎯 How It Works
The package provides:
- Core functions -
chunk,chunkInto,chunkBalanced,chunkApprox - Size variants -
chunkMinSize,chunkMaxSize,chunkExact - Special splits -
chunkOverlapping,chunkBy,chunkFirst,chunkLast - Processing -
chunkAndProcess,chunkWithProgress,chunkAsync,chunkAndCollect - Iteration -
chunkIterator,LazyChunkIterator - Utilities -
getChunkSize,getChunkCount,getChunkIndex,getChunk,flattenChunks,validateChunkOptions - Classes -
ChunkProcessor,LazyChunkIterator
🎨 What It's Useful For
- Pagination - Split results into pages
- Batch Processing - Process data in chunks (API calls, DB writes)
- Data Visualization - Split data into chart segments
- Sliding Windows - Moving averages, time-series analysis
- Parallel Processing - Distribute work across workers
- Lazy Evaluation - Process large datasets without loading all into memory
💡 Usage Examples
Basic Chunking
import { chunk } from '@chaisser/chunk-array';
chunk([1, 2, 3, 4, 5, 6, 7], 3);
// [[1, 2, 3], [4, 5, 6], [7]]
chunk([], 3);
// []Split Into N Chunks
import { chunkInto } from '@chaisser/chunk-array';
chunkInto([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3);
// [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]Balanced Chunks
import { chunkBalanced } from '@chaisser/chunk-array';
chunkBalanced([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 3);
// [[1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]Overlapping Chunks (Sliding Window)
import { chunkOverlapping } from '@chaisser/chunk-array';
chunkOverlapping([1, 2, 3, 4, 5], 3, 1);
// Sliding window of size 3, overlap of 1Exact Size with Padding
import { chunkExact } from '@chaisser/chunk-array';
chunkExact([1, 2, 3, 4, 5], 2, 0);
// [[1, 2], [3, 4], [5, 0]]Chunk by Predicate
import { chunkBy } from '@chaisser/chunk-array';
chunkBy([1, 2, 3, 4, 5], (_, i) => i % 2 === 1);
// Split before odd indices: [[1], [2], [3], [4], [5]]First and Last Chunk
import { chunkFirst, chunkLast } from '@chaisser/chunk-array';
chunkFirst([1, 2, 3, 4, 5], 2); // [1, 2]
chunkLast([1, 2, 3, 4, 5], 2); // [5]
chunkFirst([], 2); // nullLazy Iterator
import { LazyChunkIterator } from '@chaisser/chunk-array';
const iterator = new LazyChunkIterator([1, 2, 3, 4, 5, 6], 2);
iterator.getTotalChunks(); // 3
iterator.next(); // [1, 2]
iterator.next(); // [3, 4]
iterator.hasNext(); // true
iterator.next(); // [5, 6]
iterator.hasNext(); // false
iterator.next(); // null
// Reset and iterate again
iterator.reset();
iterator.next(); // [1, 2]Generator Iterator
import { chunkIterator } from '@chaisser/chunk-array';
for (const c of chunkIterator([1, 2, 3, 4, 5], 2)) {
console.log(c);
}
// [1, 2]
// [3, 4]
// [5]Process Chunks
import { chunkAndProcess } from '@chaisser/chunk-array';
const sums = chunkAndProcess([1, 2, 3, 4, 5, 6], 2, c => c.reduce((a, b) => a + b, 0));
// [3, 7, 11]Async Processing
import { chunkAsync } from '@chaisser/chunk-array';
const results = await chunkAsync(
[1, 2, 3, 4, 5, 6],
2,
async (c) => {
const res = await fetch('/api', { method: 'POST', body: JSON.stringify(c) });
return res.json();
}
);Process with Progress
import { chunkWithProgress } from '@chaisser/chunk-array';
const { results, progressUpdates } = chunkWithProgress(
[1, 2, 3, 4, 5, 6],
2,
(chunk) => chunk.reduce((a, b) => a + b, 0)
);
// results: [3, 7, 11]
// progressUpdates: [33.33, 66.66, 100]ChunkProcessor Class
import { ChunkProcessor } from '@chaisser/chunk-array';
const processor = new ChunkProcessor<number>(2);
processor.setChunks([[1, 2], [3, 4], [5, 6]]);
processor.nextChunk(); // [1, 2]
processor.hasMore(); // true
processor.nextChunk(); // [3, 4]
processor.processRemaining(c => c); // [[5, 6]]
processor.reset();
processor.getChunks(); // []Utilities
import { getChunkSize, getChunkCount, getChunkIndex, getChunk, flattenChunks } from '@chaisser/chunk-array';
getChunkSize(10, 3); // 4
getChunkCount(10, 3); // 4
getChunkIndex([1, 2, 3, 4, 5], 3, 2); // 1
getChunk([1, 2, 3, 4, 5], 3, 2); // [3, 4]
flattenChunks([[1, 2], [3, 4]]); // [1, 2, 3, 4]📚 API Reference
Core Chunking
| Function | Signature | Description |
|---|---|---|
| chunk(array, size) | (T[], number) → T[][] | Split into chunks of size |
| chunkWithOptions(array, options) | (T[], ChunkOptions) → T[][] | Chunk with size and preserveTail options |
| chunkInto(array, count) | (T[], number) → T[][] | Split into count chunks |
| chunkApprox(array, target) | (T[], number) → T[][] | Approximately target chunks |
| chunkBalanced(array, count) | (T[], number) → T[][] | Evenly balanced chunks |
| chunkOverlapping(array, size, overlap) | (T[], number, number) → T[][] | Overlapping/sliding window chunks |
| chunkMinSize(array, minSize) | (T[], number) → T[][] | Chunks with minimum size |
| chunkMaxSize(array, maxSize) | (T[], number) → T[][] | Chunks with maximum size |
| chunkExact(array, size, filler) | (T[], number, T) → T[][] | Exact size, pad last chunk |
| chunkBy(array, predicate) | (T[], (item, index) => boolean) → T[][] | Split by custom predicate |
| chunkFirst(array, size) | (T[], number) → T[] \| null | Get first chunk only |
| chunkLast(array, size) | (T[], number) → T[] \| null | Get last chunk only |
Processing
| Function | Description |
|---|---|
| chunkAndProcess(array, size, fn) | Process each chunk synchronously |
| chunkAsync(array, size, fn) | Process chunks sequentially with async fn |
| chunkWithProgress(array, size, fn) | Process with progress tracking |
| chunkAndCollect(array, size, collector) | Collect results into custom accumulator |
| flattenChunks(chunks) | Flatten T[][] into T[] |
Iteration
| Function / Class | Description |
|---|---|
| chunkIterator(array, size) | Generator yielding chunks |
| LazyChunkIterator | Class with next(), hasNext(), reset(), getTotalChunks() |
ChunkProcessor
const p = new ChunkProcessor<T>(chunkSize);
p.setChunks(chunks); // Set chunks to process
p.getChunks(); // Get current chunks
p.nextChunk(); // Get next chunk (or null)
p.hasMore(); // Check if more chunks available
p.processRemaining(fn); // Process all remaining chunks
p.reset(); // Clear all chunksLazyChunkIterator
const it = new LazyChunkIterator<T>(array, chunkSize);
it.next(); // Next chunk or null
it.hasNext(); // More chunks available?
it.reset(); // Reset to start
it.getTotalChunks(); // Total chunk count
it.getCurrentChunkNumber(); // Current 1-based chunk number
it.getIndex(); // Current byte index in arrayUtilities
| Function | Description |
|---|---|
| getChunkSize(arrayLength, chunkCount) | Calculate chunk size |
| getChunkCount(arrayLength, chunkSize) | Calculate chunk count |
| getChunkIndex(array, element, chunkSize) | Get chunk index for element |
| getChunk(array, element, chunkSize) | Get chunk containing element |
| validateChunkOptions(options) | Validate options, throws on invalid |
🔗 Related Packages
Explore our other utility packages in the @chaisser namespace:
- @chaisser/chunk-array (this package) - Split arrays into chunks
- @chaisser/string-wizard - Advanced string manipulation
- @chaisser/type-guard - Runtime type guards and validators
- @chaisser/uuid-v7 - Time-ordered UUID v7 generator
- @chaisser/wait-for - Promise-based wait utilities
- @chaisser/regex-humanizer - Regex to human-readable descriptions
- @chaisser/password-strength - Password strength checker
- @chaisser/human-time - Human-readable time formatting
- @chaisser/obj-path - Safe dot-notation object access
- @chaisser/debounce-throttle - Rate limiting utilities
- @chaisser/color-utils - Color conversion utilities
- @chaisser/deep-clone - Deep cloning functions
- @chaisser/array-group-by - Array grouping utilities
- @chaisser/merge-objects - Object merge utilities
- @chaisser/event-emitter - Typed event emitter
🔒 License
MIT - Free to use in personal and commercial projects
👨 Developed by
Doruk Karaboncuk [email protected]
📄 Repository
- GitHub: @chaisser
- NPM: @chaisser/chunk-array
🤝 Contributing
Contributions are welcome! Feel free to:
- Report bugs
- Suggest new features
- Submit pull requests
- Improve documentation
📞 Support
For issues, questions, or suggestions, please reach out through:
- Email: [email protected]
- GitHub Issues: Create an issue
Made with ❤️ by @chaisser
