You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

77 lines
1.7 KiB

3 years ago
/**
* Obliterator Combinations Function
* ==================================
*
* Iterator returning combinations of the given array.
*/
var Iterator = require('./iterator.js');
/**
* Helper mapping indices to items.
*/
function indicesToItems(target, items, indices, r) {
for (var i = 0; i < r; i++) target[i] = items[indices[i]];
}
/**
* Combinations.
*
* @param {array} array - Target array.
* @param {number} r - Size of the subsequences.
* @return {Iterator}
*/
module.exports = function combinations(array, r) {
if (!Array.isArray(array))
throw new Error(
'obliterator/combinations: first argument should be an array.'
);
var n = array.length;
if (typeof r !== 'number')
throw new Error(
'obliterator/combinations: second argument should be omitted or a number.'
);
if (r > n)
throw new Error(
'obliterator/combinations: the size of the subsequences should not exceed the length of the array.'
);
if (r === n) return Iterator.of(array.slice());
var indices = new Array(r),
subsequence = new Array(r),
first = true,
i;
for (i = 0; i < r; i++) indices[i] = i;
return new Iterator(function next() {
if (first) {
first = false;
indicesToItems(subsequence, array, indices, r);
return {value: subsequence, done: false};
}
if (indices[r - 1]++ < n - 1) {
indicesToItems(subsequence, array, indices, r);
return {value: subsequence, done: false};
}
i = r - 2;
while (i >= 0 && indices[i] >= n - (r - i)) --i;
if (i < 0) return {done: true};
indices[i]++;
while (++i < r) indices[i] = indices[i - 1] + 1;
indicesToItems(subsequence, array, indices, r);
return {value: subsequence, done: false};
});
};