@onesy/utils
Version:
137 lines (136 loc) • 6.57 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const is_1 = __importDefault(require("./is"));
const unique_1 = __importDefault(require("./unique"));
const permutation_1 = __importDefault(require("./permutation"));
const variationWithRepetition_1 = __importDefault(require("./variationWithRepetition"));
const optionsDefault = {
response: 'array',
};
// m - array, n - items
// m! / (m - n)!
function variation(value_, items_ = 0, options_ = {}) {
const options = Object.assign(Object.assign({}, optionsDefault), options_);
if ((0, is_1.default)('array', value_)) {
const value = (0, unique_1.default)(value_);
const items = (0, is_1.default)('number', items_) ? items_ : 0;
const length = value.length;
if (items < 1)
return [value];
if (items === 1)
return value.map(item_ => [item_]);
// If items is same is length it's a permutation method
if (length === items)
return (0, permutation_1.default)(value, options);
// If items is more than length it's a variationWithRepetition method
if (items > length)
return (0, variationWithRepetition_1.default)(value, items, options);
// And other use case, we have less items than the amount of values
// [0, 1, 2, 3, 4], or whatever
const allIndexes = [...Array(length).keys()];
let item = [...Array(items).keys()];
let index = items - 2;
let availableIndexes = allIndexes.filter(i_ => item.slice(0, -1).indexOf(i_) === -1);
const availableIndexesLength = availableIndexes.length;
let updated = false;
const response = [];
if (options.response === 'array') {
first: while (index >= 0) {
if (updated) {
index = items - 2;
updated = false;
}
// Update available indexes
availableIndexes = allIndexes.filter(i_ => item.slice(0, -1).indexOf(i_) === -1);
// Add all the values from available indexes to the last index
for (let l = 0; l < availableIndexesLength; l++) {
item[item.length - 1] = availableIndexes[l];
const item_ = item.slice().map(index_ => value[index_]);
response.push(item_);
}
// Move to the left of the values
while (true) {
if (item[index] === length - 1) {
index--;
if (index < 0)
break;
updated = true;
}
else {
// Make this value a next one in available based on it's current and all values from the left
item[index] = allIndexes.filter(i_ => item.slice(0, index + 1).indexOf(i_) === -1 && i_ > item[index])[0];
if (item[index] === undefined) {
index--;
if (index < 0)
break;
updated = true;
}
else {
// Make rest of item values unique based on all the left values
const part = item.slice(0, index + 1);
item = [...part, ...allIndexes.filter(i_ => part.indexOf(i_) === -1).slice(0, items - part.length)];
if (item[1] === undefined || item[index] === undefined)
break first;
break;
}
}
}
if (item[0] === length && item[1] === length - 1)
break;
}
return response;
}
if (options.response === 'yield')
return function* () {
first: while (index >= 0) {
if (updated) {
index = items - 2;
updated = false;
}
// Update available indexes
availableIndexes = allIndexes.filter(i_ => item.slice(0, -1).indexOf(i_) === -1);
// Add all the values from available indexes to the last index
for (let l = 0; l < availableIndexesLength; l++) {
item[item.length - 1] = availableIndexes[l];
const item_ = item.slice().map(index_ => value[index_]);
yield item_;
response.push(item_);
}
// Move to the left of the values
while (true) {
if (item[index] === length - 1) {
index--;
if (index < 0)
break;
updated = true;
}
else {
// Make this value a next one in available based on it's current and all values from the left
item[index] = allIndexes.filter(i_ => item.slice(0, index + 1).indexOf(i_) === -1 && i_ > item[index])[0];
if (item[index] === undefined) {
index--;
if (index < 0)
break;
updated = true;
}
else {
// Make rest of item values unique based on all the left values
const part = item.slice(0, index + 1);
item = [...part, ...allIndexes.filter(i_ => part.indexOf(i_) === -1).slice(0, items - part.length)];
if (item[1] === undefined || item[index] === undefined)
break first;
break;
}
}
}
if (item[0] === length && item[1] === length - 1)
break;
}
return response;
};
}
}
exports.default = variation;
;