Iterate an array as a pair (current, next) in JavaScript

前端 未结 13 1000
情话喂你
情话喂你 2020-12-09 09:06

In the question Iterate a list as pair (current, next) in Python, the OP is interested in iterating a Python list as a series of current, next pairs. I have th

13条回答
  •  旧时难觅i
    2020-12-09 09:54

    Here's a generic functional solution without any dependencies:

    const nWise = (n, array) => {
      iterators = Array(n).fill()
        .map(() => array[Symbol.iterator]());
      iterators
        .forEach((it, index) => Array(index).fill()
          .forEach(() => it.next()));
      return Array(array.length - n + 1).fill()
        .map(() => (iterators
          .map(it => it.next().value);
    };
    
    const pairWise = (array) => nWise(2, array);
    

    I know doesn't look nice at all but by introducing some generic utility functions we can make it look a lot nicer:

    const sizedArray = (n) => Array(n).fill();
    

    I could use sizedArray combined with forEach for times implementation, but that'd be an inefficient implementation. IMHO it's ok to use imperative code for such a self-explanatory function:

    const times = (n, cb) => {
      while (0 < n--) {
        cb();
      }
    }
    

    If you're interested in more hardcore solutions, please check this answer.

    Unfortunately Array.fill only accepts a single value, not a callback. So Array(n).fill(array[Symbol.iterator]()) would put the same value in every position. We can get around this the following way:

    const fillWithCb = (n, cb) => sizedArray(n).map(cb);
    

    The final implementation:

    const nWise = (n, array) => {
      iterators = fillWithCb(n, () => array[Symbol.iterator]());
      iterators.forEach((it, index) => times(index, () => it.next()));
      return fillWithCb(
        array.length - n + 1,
        () => (iterators.map(it => it.next().value),
      );
    };
    

    By changing the parameter style to currying, the definition of pairwise would look a lot nicer:

    const nWise = n => array => {
      iterators = fillWithCb(n, () => array[Symbol.iterator]());
      iterators.forEach((it, index) => times(index, () => it.next()));
      return fillWithCb(
        array.length - n + 1,
        () => iterators.map(it => it.next().value),
      );
    };
    
    const pairWise = nWise(2);
    

    And if you run this you get:

    > pairWise([1, 2, 3, 4, 5]);
    // [ [ 1, 2 ], [ 2, 3 ], [ 3, 4 ], [ 4, 5 ] ]
    

提交回复
热议问题