3

Let's say I have an array and I want to iterate over them N at a time. I can use a simple nested loop

const array = ['a','b','c','d','e','f','g','h'];
const step = 3;
for (let i = 0; i < array.length; i += step) {
   const end = Math.min(i + step, array.length);
   console.log("page:", i / step);
   for (let j = i; j < end; ++j) {
     const element = array[j];
     console.log("  ", element);
   }
}

outputs:

page: 0
   a
   b
   c
page: 1
   d
   e
   f
page: 2
   g
   h

But I'm wondering if there's a more modern way, forEach like way in JavaScript now-a-days. Imagine:

// pseudo code
const chunkSize = 3
forEachByChunk(array, chunkSize, (subArray, chunkNdx, startingNdxInParentArray) => {
  console.log("page:", chunkNdx);
  subArray.forEach((element) => { console.log("  ", element); });
});

Note: I can write my own forEachByChunk

function forEachByChunk(array, chunkSize, fn) {
  const end = array.length;
  for (let i = 0; i < end; i += chunkSize) {
    fn(array.slice(i, i + chunkSize), i / chunkSize, i);
  }
}

I'm just wondering if there isn't already some built in modern way to do this in JavaScript. Or maybe a more generic version.

gman
  • 100,619
  • 31
  • 269
  • 393
  • 1
    No, pretty much all built-ins will iterate over the entire array without skipping indices. You can use a condition inside the callback, but it's more efficient to just use a `for` loop like you do in the first example. Adding to native prototypes is generally not a very good idea either – adeneo Aug 27 '17 at 04:42
  • I implemented array.stride exactly for this reason. Search for it on npm. Since this is self-promotion I'm not putting it down as an answer unless requested – slebetman Aug 27 '17 at 05:37
  • Also, I've been hoping to propose array.stride for ES8 but have not found time to write the proposal – slebetman Aug 27 '17 at 05:37
  • @slebetman There's no good reason to have a native chunk iterator for two reasons. First, it's easy to build a chunk iterator from an element iterator. Second, it doesn't offer any performance benefits because you have to iterate over each element in the chunk to copy the entire chunk anyway. For example, if you use `slice` to create the chunk then you're iterating over every element of the chunk in order to copy it anyway. – Aadit M Shah Aug 27 '17 at 06:04
  • @AaditMShah: There's always a good reason for code clarity. Just like the `.bind()` method of Functions. There is no good reason to have it in the language by your reasoning because you can implement it. For a chunk iterator you can definitely increase performance by implementing it in C – slebetman Aug 27 '17 at 06:12
  • @slebetman I disagree. First, if you're worried about code clarity then what's wrong with defining your own `stride` function? Just because JavaScript provides `bind` doesn't mean that it needs to provide every convenience feature. Second, there's no need to be worried about performance because modern JavaScript engines already heavily optimize loops. Whether you implement a chunk iterator in JavaScript or in C, performance is going to be relatively similar. Third, it's generally never the case that the performance of a chunk iterator is the bottleneck in any algorithm. Premature optimization? – Aadit M Shah Aug 27 '17 at 06:26
  • @AaditMShah I wasn't worried about performance, you brought it up, I was just answering your performance comment. As is, array operations are incomplete. There is no stride feature and there is no merge feature (other languages sometimes call them unzip and zip). My implementation of stride solves the lack of unzip. I have another implementation Array.and that tries to address the lack of zip. IMHO, my implementation of stride is better than how zip is implemented in other languages with tcl's foreach being the only superior implementation. – slebetman Aug 27 '17 at 13:57
  • @AaditMShah: Also, defining your own stride function is perfectly fine in my opinion. Just like it was perfectly fine for jQuery and Dojo and lodash and prototype to define their own foreach function years ago when javascript did not have Array.prototype.foreach. But we can learn about what is lacking in the language's standard library and improve it to greatly improve code reuse. – slebetman Aug 27 '17 at 14:01
  • Your question is ambiguous. Do you want a **more modern way**, or a **built-in modern way**? –  Aug 28 '17 at 06:35

3 Answers3

2

I'm just wondering if there isn't already some built in modern way to do this in JavaScript.

No, there is not.

Or maybe a more generic version.

There are many user versions. Google for "javascript partition array". Here's something to get you started.

-1

Check out chunk from lodash. It does exactly what you want.

Check out lodash and rambda in general. They have pretty much any general helper method you can think of.

_.chunk([1, 2, 3, 4, 5, 6, 7, 8], 3) returns [[1, 2, 3], [4, 5, 6], [7, 8]]

Edit: If you are looking for how such a thing could be implemented using some of the new syntax, this is how you could do it.

const chunk = size => list =>
  list
    .map((value, index) => ({ value, step: index % size }))
    .reduce(
      (accum, item) => {
        const { value, step } = item;
        if (step === 0) return [[value], ...accum];
        const [head, ...tail] = accum;
        return [[...head, value], ...tail];
      },
      [],
    ).slice().reverse();

I hope you don't use this though. This is not tested, you are probably much better off with lodash.

jaihindhreddy
  • 358
  • 2
  • 7
-2

use slice and map can solve the problem

const step = 3;
const array = ['a','b','c','d','e','f','g','h'];
var pages = array.map( (letter,index)=> index%step===0 ? array.slice(index,index+step) : [] )
.filter((page)=>page.length>=0);
Zhang Bruce
  • 884
  • 1
  • 8
  • 23
  • 2
    But the OP seems to be looking for a built-in chunk iterator. Or a more generic version. Of which this is neither. –  Aug 27 '17 at 05:02
  • splice and map is built in generic method, I don't understand 2 down vote for this, and 2 up vote for an answer saying no there's not – Zhang Bruce Aug 27 '17 at 16:59
  • The question is, "is there a built-in partitioning method". The correct answer is "no, there is not". If the OP was looking for a home-grown user-written algorithm for partitioning, there are hundreds available via a simple search that frankly are better than yours. –  Aug 28 '17 at 03:27