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.
95 lines
1.9 KiB
95 lines
1.9 KiB
/**
|
|
* Obliterator Permutations Function
|
|
* ==================================
|
|
*
|
|
* Iterator returning permutations 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]];
|
|
}
|
|
|
|
/**
|
|
* Permutations.
|
|
*
|
|
* @param {array} array - Target array.
|
|
* @param {number} r - Size of the subsequences.
|
|
* @return {Iterator}
|
|
*/
|
|
module.exports = function permutations(array, r) {
|
|
if (!Array.isArray(array))
|
|
throw new Error(
|
|
'obliterator/permutations: first argument should be an array.'
|
|
);
|
|
|
|
var n = array.length;
|
|
|
|
if (arguments.length < 2) r = n;
|
|
|
|
if (typeof r !== 'number')
|
|
throw new Error(
|
|
'obliterator/permutations: second argument should be omitted or a number.'
|
|
);
|
|
|
|
if (r > n)
|
|
throw new Error(
|
|
'obliterator/permutations: the size of the subsequences should not exceed the length of the array.'
|
|
);
|
|
|
|
var indices = new Uint32Array(n),
|
|
subsequence = new Array(r),
|
|
cycles = new Uint32Array(r),
|
|
first = true,
|
|
i;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
indices[i] = i;
|
|
|
|
if (i < r) cycles[i] = n - i;
|
|
}
|
|
|
|
i = r;
|
|
|
|
return new Iterator(function next() {
|
|
if (first) {
|
|
first = false;
|
|
indicesToItems(subsequence, array, indices, r);
|
|
return {value: subsequence, done: false};
|
|
}
|
|
|
|
var tmp, j;
|
|
|
|
i--;
|
|
|
|
if (i < 0) return {done: true};
|
|
|
|
cycles[i]--;
|
|
|
|
if (cycles[i] === 0) {
|
|
tmp = indices[i];
|
|
|
|
for (j = i; j < n - 1; j++) indices[j] = indices[j + 1];
|
|
|
|
indices[n - 1] = tmp;
|
|
|
|
cycles[i] = n - i;
|
|
return next();
|
|
} else {
|
|
j = cycles[i];
|
|
tmp = indices[i];
|
|
|
|
indices[i] = indices[n - j];
|
|
indices[n - j] = tmp;
|
|
|
|
i = r;
|
|
|
|
indicesToItems(subsequence, array, indices, r);
|
|
return {value: subsequence, done: false};
|
|
}
|
|
});
|
|
};
|