UNPKG

@amaui/utils

Version:
108 lines (89 loc) 3.79 kB
import is from './is'; import unique from './unique'; import equalDeep from './equalDeep'; const optionsDefault = { response: 'array' }; // m - array // m! export default function permutation(value_) { let options_ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; const options = { ...optionsDefault, ...options_ }; if (is('array', value_)) { const value = unique(value_); const length = value.length; const items = length; if (items < 1) return [value]; if (items === 1) return value.map(item_ => [item_]); if (items === 2) return [value, [value[1], value[0]]]; // 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 - 3; let updated = false; const response = []; if (options.response === 'array') { while (index >= 0) { if (updated) { index = items - 3; updated = false; } // Add item to response response.push(item.slice().map(index_ => value[index_])); // Swap last two and add item to response [item[length - 2], item[length - 1]] = [item[length - 1], item[length - 2]]; response.push(item.slice().map(index_ => value[index_])); if (item[0] === length - 1 && item[1] === length - 2 && equalDeep(item, value.slice().reverse())) break; // Move to the left of the values while (true) { const firstPart = item.slice(0, index + 1); const indexNew = allIndexes.filter(index_ => index_ > item[index] && firstPart.indexOf(index_) === -1)[0]; if (!indexNew) { index--; if (index < 0) break; updated = true; } else { // Increment the index // Make rest of the items unique based on the left over indexes from allIndexes item[index] = indexNew; // 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)]; break; } } } return response; } if (options.response === 'yield') return function* () { while (index >= 0) { if (updated) { index = items - 3; updated = false; } // Add item to response let item_ = item.slice().map(index_ => value[index_]); yield item_; response.push(item_); // Swap last two and add item to response [item[length - 2], item[length - 1]] = [item[length - 1], item[length - 2]]; item_ = item.slice().map(index_ => value[index_]); yield item_; response.push(item_); if (item[0] === length - 1 && item[1] === length - 2 && equalDeep(item, value.slice().reverse())) break; // Move to the left of the values while (true) { const firstPart = item.slice(0, index + 1); const indexNew = allIndexes.filter(index_ => index_ > item[index] && firstPart.indexOf(index_) === -1)[0]; if (!indexNew) { index--; if (index < 0) break; updated = true; } else { // Increment the index // Make rest of the items unique based on the left over indexes from allIndexes item[index] = indexNew; // 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)]; break; } } } return response; }; } }