Home Reference Source

src/partition.js

import mapIndexed from './mapIndexed';

/**
 * 集合を分割します。分割した余りは返されません。
 *
 * @param {*[]} args - [n、step、pad、coll]。nは要素数、stepは分割する位置(省略した場合はnと同じ)、padは要素が不足した場合に追加する値(省略した場合はnull)、collは集合。
 *
 * @return {iterator} 分割された集合のイテレーター
 *
 * @example
 * partition(3,               [0, 1, 2, 3, 4, 5, 6, 7]);  // [[0, 1, 2], [3, 4, 5]]のイテレーター
 * partition(3, 4,            [0, 1, 2, 3, 4, 5, 6, 7]);  // [[0, 1, 2], [4, 5, 6]]のイテレーター
 * partition(3, 2,            [0, 1, 2, 3, 4, 5, 6, 7]);  // [[0, 1, 2], [2, 3, 4], [4, 5, 6]]のイテレーター
 * partition(3, 3, [0, 0, 0], [0, 1, 2, 3, 4, 5, 6, 7]);  // [[0, 1, 2], [3, 4, 5], [6, 7, 0]]のイテレーター
 */
export default function* partition(...args) {
  const [n, step, pad, coll] = (() => {
    switch (args.length) {
    case 0:
      throw 'Invalid arguments';

    case 1:
      throw 'Invalid arguments';

    case 2:
      return [args[0], args[0], null, args[1]];

    case 3:
      return [args[0], args[1], null, args[2]];

    default:
      return args;
    }
  })();

  const xss = [];

  for (const [i, x] of mapIndexed(Array.of, coll)) {
    if (i % step === 0) {
      xss.push([]);
    }

    if (xss.length > 0) {
      for (const xs of xss) {
        xs.push(x);
      }

      if (xss[0].length === n) {
        yield xss[0];

        xss.shift();
      }
    }
  }

  if (pad && xss.length > 0) {
    yield xss[0].concat(pad).slice(0, n);
  }
}