77 lines
1.7 KiB
JavaScript
77 lines
1.7 KiB
JavaScript
/**
|
|
* 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};
|
|
}
|
|
|
|
if (indices[r - 1]++ < n - 1) {
|
|
indicesToItems(subsequence, array, indices, r);
|
|
return {value: subsequence};
|
|
}
|
|
|
|
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};
|
|
});
|
|
};
|