Efficient Techniques for Chunking Arrays in JavaScript: A Performance Comparison

hallowshaw

Rhitam Chaudhury

Posted on July 6, 2024

Efficient Techniques for Chunking Arrays in JavaScript: A Performance Comparison

Chunking an array means splitting it into smaller arrays of a specified size. This technique is useful for data processing, pagination, and more. In this blog, we'll explore four methods to chunk an array and compare their performance.

Initial Setup:

First, let's create an array of numbers from 1 to 10:

const arr = Array.from({ length: 10 }, (_, i) => i + 1);
Enter fullscreen mode Exit fullscreen mode

Array.from() is used to generate an array with elements from 1 to 10. Now, we'll look at four ways to chunk this array.

Method 1: Using a For Loop

function chunkArr(arr, size) {
    let res = [];
    for (let i = 0; i < arr.length; i += size) {
        res.push(arr.slice(i, size + i));
    }
    return res;
}

console.time("for");
console.log(chunkArr(arr, 2));
console.timeEnd("for");
Enter fullscreen mode Exit fullscreen mode

Output:

[ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ], [ 9, 10 ] ]
for: 4.363ms
Enter fullscreen mode Exit fullscreen mode

Explanation:

This function iterates through the array in steps of the specified chunk size. It slices the array at each step and adds the resulting sub-array to the result array (res). The performance measurement shows it took about 4.363 milliseconds.

Detailed Breakdown:

  • Initialization: A result array res is initialized to hold the chunks.
  • Looping: A for loop iterates over the array with a step size equal to the chunk size.
  • Slicing: Within each iteration, a sub-array is created using slice and added to res.
  • Return: After the loop completes, the function returns the result array containing all chunks.

Method 2: Using Array.reduce()

function chunkArr2(arr, size) {
    if (size <= 0) throw new Error('Chunk size must be a positive integer');
    return arr.reduce((acc, _, i) => {
        if (i % size === 0) acc.push(arr.slice(i, i + size));
        return acc;
    }, []);
}

console.time("reduce");
console.log(chunkArr2(arr, 2));
console.timeEnd("reduce");
Enter fullscreen mode Exit fullscreen mode

Output:

[ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ], [ 9, 10 ] ]
reduce: 0.069ms
Enter fullscreen mode Exit fullscreen mode

Explanation:

Here Array.reduce() is used to build the chunked array. It checks if the current index is a multiple of the chunk size and slices the array accordingly. This method is significantly faster, taking only about 0.069 milliseconds.

Detailed Breakdown:

  • Validation: The function checks if the chunk size is valid.
  • Reducer Function: The reduce method iterates over the array. For each element, it checks if the index is a multiple of the chunk size.
  • Slicing: When the index is a multiple of the chunk size, it slices the array and pushes the sub-array into the accumulator.
  • Return: The accumulator containing the chunked arrays is returned.

Method 3: Using Array.splice()

let [list, chunkSize] = [arr, 2];

console.time('splice');
list = [...Array(Math.ceil(list.length / chunkSize))].map(_ => list.splice(0, chunkSize));
console.timeEnd('splice');
console.log(list);
Enter fullscreen mode Exit fullscreen mode

Output:

[ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ], [ 9, 10 ] ]
splice: 0.048ms
Enter fullscreen mode Exit fullscreen mode

Explanation:

This approach uses Array.splice() in combination with Array.map() to chunk the array. It creates a new array with the required number of chunks and uses splice() to remove and collect chunks from the original array. This method is also very fast, taking about 0.048 milliseconds.

Detailed Breakdown:

  • Initialization: Create an array with the number of chunks needed.
  • Mapping: Use map to iterate over the new array.
  • Splicing: Within each iteration, use splice to remove and collect chunks from the original array.
  • Return: The resulting array of chunks is returned.

Method 4: Recursive Approach

const chunk = function(array, size) {
    if (!array.length) {
        return [];
    }
    const head = array.slice(0, size);
    const tail = array.slice(size);
    return [head, ...chunk(tail, size)];
};

console.time('recursive');
console.log(chunk(arr, 2));
console.timeEnd('recursive');
Enter fullscreen mode Exit fullscreen mode

Output:

[ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ], [ 9, 10 ] ]
recursive: 4.372ms
Enter fullscreen mode Exit fullscreen mode

Explanation:

This recursive method splits the array into the first chunk (head) and the remaining elements (tail). It then recursively processes the tail, concatenating the results. While more elegant, this method is slower than the reduce and splice methods, taking about 4.372 milliseconds.

Detailed Breakdown:

  • Base Case: If the array is empty, return an empty array.
  • Slicing: Split the array into the head (first chunk) and the tail (remaining elements).
  • Recursion: Recursively process the tail and concatenate the results with the head.
  • Return: The concatenated result is returned.

All four methods successfully chunk the array into sub-arrays of the specified size. However, their performance varies significantly:

  • For Loop: 4.363ms
  • Reduce: 0.069ms
  • Splice: 0.048ms
  • Recursive: 4.372ms

The splice and reduce methods are the fastest, making them preferable for performance-critical applications. While functional, the for loop and recursive methods are slower and might be less suitable for large datasets.

Recommendations

  • Performance: For optimal performance, use the splice or reduce methods.
  • Readability: The recursive method offers more readability and elegance, but at the cost of performance.
  • Flexibility: The for loop method is straightforward and easy to understand, suitable for simple use cases.

Thank you for reading!

💖 💪 🙅 🚩
hallowshaw
Rhitam Chaudhury

Posted on July 6, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related