combinational sum- how to write test correctly JavaScript - javascript

I need to test Combinational Sum I algorithm using JavaScript. I have done all things in html, but I don't know how to call function (in script.js), which contain Combinational Sum I algorithm, correctly. Does anybody know how to call it? how to calculate? how to write test?
let botun=document.getElementById('botun');
//including variables
botun.onclick=function(){
let niz=document.getElementById('input').value;
let target=document.getElementById('target').value;
//convert string in array
let nizInt=niz.split(' ').map(Number);
//convert element of array in Int
let nizIntNovi=[];
for(var i=0; i<nizInt.length; i++) {
nizInt[i] = parseInt(nizInt[i], 10);
nizIntNovi[i]=nizInt[i];
}
console.log(nizIntNovi);
//calling function
let meduRez=combinationalSum(nizIntNovi,target);
console.log(meduRez);
}
// Javascript program to find all combinations that
// sum to a given value
var combinationalSum=function(candidates,target){
//global result
const result=[];
candidates.sort((a,b)=>a-b);
//dfs recursive helper
const dfs=(i,candidates,target,slate)=>{
//backtracking case
if(target<0) return;
//base case
if(target===0){
result.push(slate.slice());
return;
}
//dfs recursive case
for(let j=i;j<candidates.lenght;j++){
slate.push(candidates[j]);
dfs(j,candidates,target-candidates[j],slate);
slate.pop();
}
}
dfs(0,candidates,target,[]);
return result;
};

You call it like in the snippet below, with some basic HTML.
Or using the console of the browser.
The function is not working right.
You can read about implementation here https://www.geeksforgeeks.org/combinational-sum/
let botun = document.getElementById('botun');
//including variables
botun.onclick = function() {
let niz = document.getElementById('input').value;
let target = document.getElementById('target').value;
//convert string in array
let nizInt = niz.split(' ').map(Number);
//convert element of array in Int
let nizIntNovi = [];
for (var i = 0; i < nizInt.length; i++) {
nizInt[i] = parseInt(nizInt[i], 10);
nizIntNovi[i] = nizInt[i];
}
console.log(nizIntNovi);
//calling function
let meduRez = combinationalSum(nizIntNovi, target);
console.log(meduRez);
}
// Javascript program to find all combinations that
// sum to a given value
var combinationalSum = function(candidates, target) {
//global result
const result = [];
candidates.sort((a, b) => a - b);
//dfs recursive helper
const dfs = (i, candidates, target, slate) => {
//backtracking case
if (target < 0) return;
//base case
if (target === 0) {
result.push(slate.slice());
return;
}
//dfs recursive case
for (let j = i; j < candidates.lenght; j++) {
slate.push(candidates[j]);
dfs(j, candidates, target - candidates[j], slate);
slate.pop();
}
}
dfs(0, candidates, target, []);
return result;
};
input {
height: 30px;
width: 100px;
line-height: 1;
}
.as-console-wrapper {
max-height: 100% !important;
}
Input: <input id="input" value="1 2 3 4"> Target: <input id="target" value="6">
<input type="button" id="botun" value="click">

There is solved problem. Task: input array of integer, input target then calculate Combinational Sum and print the smallest array of Combinational Sum.
For example: Input: [2,4,6] Target:4. Output will be 1, because Combinational Sum prints (2+2),(4). Smaller array is 4 and it contains one element so 1 will be output!
Code:
let botun=document.getElementById('botun');
let nizSplitNew=[];
let targetNew;
let brojac;
let array=[];
let min;
var rezultat=document.getElementById("rezl");
//including variables
botun.onclick=function(){
let niz=document.getElementById('input').value;
let target=document.getElementById('target').value;
//convert string in array
let nizSplit=niz.split(',').map(Number);
//convert element of array in Int
for(var i=0; i<nizSplit.length; i++) {
nizSplitNew[i] = parseInt(nizSplit[i], 10);
}
console.log(nizSplitNew);
targetNew = parseInt(target, 10);
//calling function
let meduRez=combinationSum(nizSplitNew,targetNew);
// Javascript program to find all combinations that
// sum to a given value
function combinationSum(arr, sum) {
let ans = new Array();
let temp = new Array();
// first do hashing since hashset does not always
// sort
// removing the duplicates using HashSet and
// Sorting the arrayList
let set = new Set([...arr]);
arr = [...set];
arr.sort()
findNumbers(ans, arr, sum, 0, temp);
return ans;
}
function findNumbers(ans, arr, sum, index, temp) {
if (sum == 0) {
// pushing deep copy of list to ans
ans.push([...temp]);
return;
}
for (let i = index; i < arr.length; i++) {
// checking that sum does not become negative
if ((sum - arr[i]) >= 0) {
// pushing element which can contribute to
// sum
temp.push(arr[i]);
findNumbers(ans, arr, sum - arr[i], i, temp);
// removing element from list (backtracking)
temp.splice(temp.indexOf(arr[i]), 1);
}
}
}
// Driver Code
// arr.push(5);
// arr.push(4);
// arr.push(8);
//let arr = []
for(let i=0;i<nizSplitNew;i++){
nizSplitNew.push(nizSplitNew[i]);
}
let sum = targetNew;
let ans = combinationSum(nizSplitNew, sum);
// If result is empty, then
// print all combinations stored in ans
for (let i = 0; i < ans.length; i++) {
brojac=0;
for (let j = 0; j < ans[i].length; j++) {
brojac=brojac+1;
}
array.push(brojac);
}
console.log(array);
min = Math.min(...array);
if (array.length == 0) {
rezultat.innerHTML=`<p>-1</p>`
}
else{
rezultat.innerHTML=`<p>${min}</p>`
}
}

Related

How to add 5 random numbers which are less than 10?

I've created two functions. One to create 5 random numbers to push them into an array. And another one to sum up the numbers. The random number generator is working and making an array perfectly. But the sum is not accurate. I'm unable to find where the problem is.
//Generates 5 random numbers smaller than 10
function pushIntoArray() {
let arr = [];
let number;
for(let i = 0; i < 5; i++) {
number = Math.floor(Math.random() * 11);
arr.push(number);
}
return arr;
}
console.log(pushIntoArray());
//Adds the numbers in arr
function sumNum(arr) {
let total = 0;
for(let i = 0; i < arr.length; i++) {
total += arr[i];
}
return total;
}
let arr = pushIntoArray();
console.log(sumNum(arr));
Because you are logging a different set of array values and checking the sum of different set of array values.
I have changed your console.log statement.
//Generates 5 random numbers smaller than 10
function pushIntoArray() {
let arr = [];
let number;
for(let i = 0; i < 5; i++) {
number = Math.floor(Math.random() * 11);
arr.push(number);
}
return arr;
}
//Adds the numbers in arr
function sumNum(arr) {
let total = 0;
for(let i = 0; i < arr.length; i++) {
total += arr[i];
}
return total;
}
let arr = pushIntoArray();
console.log(arr);
console.log(sumNum(arr));
You are not performing the sum on the array that you logged in the console. What you are logging is
console.log(pushIntoArray()); // This is displayed in the console
But then you are generating a ney array by calling
let arr = pushIntoArray();
BUT you are performing the sum on the arr array not the one that is displayed in the console.
console.log(sumNum(arr)); // you did not console.log(arr)
The function works correctly, you are just calling it on the wrong thing.
the function is working correctly but you are logging a different array of random numbers and calculating the sum of a different array.
//Generates 5 random numbers smaller than 10
function pushIntoArray() {
let arr = [];
let number;
for(let i = 0; i < 5; i++) {
number = Math.floor(Math.random() * 11);
arr.push(number);
}
return arr;
}
// this array is different (this is not passed to the sumNum function)
console.log(pushIntoArray());
//Adds the numbers in arr
function sumNum(arr) {
let total = 0;
for(let i = 0; i < arr.length; i++) {
total += arr[i];
}
return total;
}
// this array is different
let arr = pushIntoArray();
console.log("sum of array:", arr)
console.log(sumNum(arr));

how to fix the function to check the same random array value

I am learning javascript, I have been able to create a function that has a parameter, the function has the task of forming an array containing a 2 character (0/1) random string of 1 parameter and the return value must be an array.
example:
console.log (generateString(2));
sample results:
['01', '11']
The problem I face is even though it's a random string, but it still has the possibility to have the same value. Suppose I run the program code
console.log (generateString(4));
and one of the results is like this:
['00', '00', '01', '10']
my question is how can I ensure that the return value of the array has no duplicate value? This is my code so far..
function generateString(num){
let newArray = [];
for(let i = 0; i < num; i++){
let randomChar = generateCharacters();
if(i >= 1 && (newArray[i - 1] === randomChar)){
randomChar = generateCharacters();
newArray.push(randomChar);
} else {
newArray.push(randomChar);
}
}
return newArray;
}
function generateCharacters(){
const chars = '01';
let result = '';
for (let j = 2; j > 0; --j){
result += chars[Math.floor(Math.random() * chars.length)];
}
return result;
}
console.log(generateString(4));
Just check for the duplicate before adding the new string.
function generateString(num){
let newArray = [];
let i =0;
while(i<num){
console.log(newArray)
let randomChar = generateCharacters();
if(newArray.indexOf(randomChar)<=-1){
newArray.push(randomChar);
i+=1;
}
}
return newArray;
}
You can use a do-while inside the for-loop and keep making new random strings until the new strings generated is not included in the previous array.
function generateString(num){
let newArray = [];
let randomChar;
for(let i = 0; i < num; i++){
do{
randomChar = generateCharacters();
}
while(newArray.includes(randomChar));
newArray.push(randomChar)
}
return newArray;
}
function generateCharacters(){
const chars = '01';
let result = '';
for (let j = 2; j > 0; --j){
result += chars[Math.floor(Math.random() * chars.length)];
}
return result;
}
console.log(generateString(4));
You can shuffle the array of all 4 possible pairs of digits:
function shuffle(a) {
for (let i = a.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
let temp = a[i];
a[i] = a[j];
a[j] = temp;
}
return a;
}
function generateString(num){
let all = ["00", "01", "10", "11"];
shuffle(all);
return all.slice(0, num); // Only take the number of elements requested
}
console.log(generateString(4));
Made changes in your generateString function. You can use set for not updating duplicates in the result. I think you need to update generateCharacters function to generate all possible strings properly.
function generateString(num){
let newArraySet = new Set();
for(let i = 0; i < num; i++){
let randomChar = generateCharacters();
while(newArraySet.has(randomChar)) {
randomChar = generateCharacters();
}
newArraySet.add(randomChar);
}
return Array.from(newArraySet);
}
function generateCharacters(){
const chars = '01';
let result = '';
for (let j = 2; j > 0; --j){
result += chars[Math.floor(Math.random() * chars.length)];
}
return result;
}
console.log(generateString(4));
When building the array you need to check to see if the random number is not already in the array before adding it to the array. This function will return true if you feed it the array in question and your "random" item you need to check.
function isInArray(myArray, arrayItemToCheck)
{
var found = myArray.find(function(arrayItem) {
return arrayItem == arrayItemToCheck;
});
return !!found
}
in your function, you change the line let randomChar = generateCharacters(); to:
let randomChar;
// loops forever until condition is met
while (true) {
randomChar = generateCharacters();
if (!isInArray(newArray, randomChar)) {
break;
}
}

Common Character Count in Strings JavaScript

Here is the problem:
Given two strings, find the number of common characters between them.
For s1 = "aabcc" and s2 = "adcaa", the output should be 3.
I have written this code :
function commonCharacterCount(s1, s2) {
var count = 0;
var str = "";
for (var i = 0; i < s1.length; i++) {
if (s2.indexOf(s1[i]) > -1 && str.indexOf(s1[i]) == -1) {
count++;
str.concat(s1[i])
}
}
return count;
}
console.log(commonCharacterCount("aabcc", "adcaa"));
It doesn't give the right answer, I wanna know where I am wrong?
There are other more efficient answers, but this answer is easier to understand. This loops through the first string, and checks if the second string contains that value. If it does, count increases and that element from s2 is removed to prevent duplicates.
function commonCharacterCount(s1, s2) {
var count = 0;
s1 = Array.from(s1);
s2 = Array.from(s2);
s1.forEach(e => {
if (s2.includes(e)) {
count++;
s2.splice(s2.indexOf(e), 1);
}
});
return count;
}
console.log(commonCharacterCount("aabcc", "adcaa"));
You can do that in following steps:
Create a function that return an object. With keys as letters and count as values
Get that count object of your both strings in the main function
Iterate through any of the object using for..in
Check other object have the key of first object.
If it have add the least one to count using Math.min()
let s1 = "aabcc"
let s2 = "adcaa"
function countChars(arr){
let obj = {};
arr.forEach(i => obj[i] ? obj[i]++ : obj[i] = 1);
return obj;
}
function common([...s1],[...s2]){
s1 = countChars(s1);
s2 = countChars(s2);
let count = 0;
for(let key in s1){
if(s2[key]) count += Math.min(s1[key],s2[key]);
}
return count
}
console.log(common(s1,s2))
After posting the question, i found that i havent looked the example well. i thought it wants unique common characters ..
and i changed it and now its right
function commonCharacterCount(s1, s2) {
var count = 0;
var str="";
for(var i=0; i<s1.length ; i++){
if(s2.indexOf(s1[i])>-1){
count++;
s2=s2.replace(s1[i],'');
}
}
return count;
}
Create 2 objects containing characters and their count for strings s1
and s2
Count the common keys in 2 objects and return count - Sum the common keys with minimum count in two strings
O(n) - time and O(n) - space complexities
function commonCharacterCount(s1, s2) {
let obj1 = {}
let obj2 = {}
for(let char of s1){
if(!obj1[char]) {
obj1[char] = 1
} else
obj1[char]++
}
for(let char of s2){
if(!obj2[char]) {
obj2[char] = 1
} else
obj2[char]++
}
console.log(obj1,obj2)
let count = 0
for(let key in obj1 ){
if(obj2[key])
count += Math.min(obj1[key],obj2[key])
}
return count
}
I think it would be a easier way to understand. :)
function commonCharacterCount(s1: string, s2: string): number {
let vs1 = [];
let vs2 = [];
let counter = 0;
vs1 = Array.from(s1);
vs2 = Array.from(s2);
vs1.sort();
vs2.sort();
let match_char = [];
for(let i = 0; i < vs1.length; i++){
for(let j = 0; j < vs2.length; j++){
if(vs1[i] == vs2[j]){
match_char.push(vs1[i]);
vs2.splice(j, 1);
break;
}
}
}
return match_char.length;
}
JavaScript ES6 clean solution. Use for...of loop and includes method.
var commonCharacterCount = (s1, s2) => {
const result = [];
const reference = [...s1];
let str = s2;
for (const letter of reference) {
if (str.includes(letter)) {
result.push(letter);
str = str.replace(letter, '');
}
}
// ['a', 'a', 'c'];
return result.length;
};
// Test:
console.log(commonCharacterCount('aabcc', 'adcaa'));
console.log(commonCharacterCount('abcd', 'aad'));
console.log(commonCharacterCount('geeksforgeeks', 'platformforgeeks'));
Cause .concat does not mutate the string called on, but it returns a new one, do:
str = str.concat(s1[i]);
or just
str += s1[i];
You can store the frequencies of each of the characters and go over this map (char->frequency) and find the common ones.
function common(a, b) {
const m1 = {};
const m2 = {};
let count = 0;
for (const c of a) m1[c] = m1[c] ? m1[c]+1 : 1;
for (const c of b) m2[c] = m2[c] ? m2[c]+1 : 1;
for (const c of Object.keys(m1)) if (m2[c]) count += Math.min(m1[c], m2[c]);
return count;
}

How to get the product of numbers gotten from combinations of datasets

I have a combinatoric script that's working fine, actually got most of it from the IBM dev website. But I want to be able to not just show the possible combinations, but also extract the numbers on each combination and get the product of the entire numbers. The project am working on mixes numbers (quantity) with strings (codename). So after combining them, i extract the number from each string and get the product of all the numbers in each combination. As shown;
[A2,B4,C5] = 2*4*5 = 40
Here is my javascript code that gets the combination, not to worry, I ran it with a test array of numbers 1-6, without the characters as shown above.
var Util = function() {
};
Util.getCombinations = function(array, size, start, initialStuff, output) {
if (initialStuff.length >= size) {
output.push(initialStuff);
} else {
var i;
for (i = start; i < array.length; ++i) {
Util.getCombinations(array, size, i + 1, initialStuff.concat(array[i]), output);
}
}
}
Util.getAllPossibleCombinations = function(array, size, output) {
Util.getCombinations(array, size, 0, [], output);
}
// Create an array that holds numbers from 1 ... 6.
var array = [];
for (var i = 1; i <= 6; ++i) {
array[i - 1] = i;
}
var output = [];
var resultArray = [];
Util.getAllPossibleCombinations(array, 4, output);
for(var j=0; j<output.length; j++) {
resultArray += output[j] + "=" + "<br />";
}
document.getElementById("test").innerHTML = resultArray;
});
I tried running this code inside the last for loop to get my multiplication, but it's just not executing, i must be doing something wrong. Here is the code;
var inputval = output[j].replace(/[^,.0-9]/g, '');
inputval = inputval.slice(0, -1);
var hoArray = inputval.split(',');
var cunt= hoArray.length;
var ans=1;
for(var m=0; m<cunt; m++)
{
ans *= hoArray[m];
}
Thanks for your assistance in advance.
walk the array then walk the string, then cast and see if it is an integer then tally and sum the product.
let array = ['A20', 'B11', 'C5'];
function getProduct(ar) {
let product = 1;
for (let x of ar) {
let semiProduct = [];
for (let i of x) {
if (Number.isInteger(+i)) {
semiProduct.push(i);
}
}
product *= semiProduct.join('');
}
return product;
}
console.log(getProduct(array))
You could also use a regular expression.
let array = ['A20', 'B11', 'C5'];
function getProduct(ar) {
let product = 1;
for (let x of ar) {
product *= x.match(/\d+/)[0];
}
return product;
}
console.log(getProduct(array))
If you want a way to generate permutations, you can utilize a generator to make things more concise.
let array = ['A20', 'B11', 'C5'];
function* permu(arr, l = arr.length) {
if (l <= 0) yield arr.slice();
else
for (var i = 0; i < l; i++) {
yield* permu(arr, l - 1);
const j = l % 2 ? 0 : i;
[arr[l - 1], arr[j]] = [arr[j], arr[l - 1]];
}
}
console.log(
Array.from(permu(array))
);
When I run that code in the console it throws an error because output[j] is an array [1,2,3,4] and it looks like you're expecting it to be a string. Arrays do not have a replace method in JS.
You should run this:
var count= hoArray.length;
var ans=1;
for(var m=0; m<count; m++)
{
ans *= hoArray[m];
}
And put output[j] instead of hoArray. And don't do any of this:
var inputval = output[j].replace(/[^,.0-9]/g, '');
inputval = inputval.slice(0, -1);
var hoArray = inputval.split(',');

JavaScript - Generating combinations from n arrays with m elements [duplicate]

This question already has answers here:
Cartesian product of multiple arrays in JavaScript
(35 answers)
Closed 1 year ago.
I'm having trouble coming up with code to generate combinations from n number of arrays with m number of elements in them, in JavaScript. I've seen similar questions about this for other languages, but the answers incorporate syntactic or library magic that I'm unsure how to translate.
Consider this data:
[[0,1], [0,1,2,3], [0,1,2]]
3 arrays, with a different number of elements in them. What I want to do is get all combinations by combining an item from each array.
For example:
0,0,0 // item 0 from array 0, item 0 from array 1, item 0 from array 2
0,0,1
0,0,2
0,1,0
0,1,1
0,1,2
0,2,0
0,2,1
0,2,2
And so on.
If the number of arrays were fixed, it would be easy to make a hard coded implementation. But the number of arrays may vary:
[[0,1], [0,1]]
[[0,1,3,4], [0,1], [0], [0,1]]
Any help would be much appreciated.
Here is a quite simple and short one using a recursive helper function:
function cartesian(...args) {
var r = [], max = args.length-1;
function helper(arr, i) {
for (var j=0, l=args[i].length; j<l; j++) {
var a = arr.slice(0); // clone arr
a.push(args[i][j]);
if (i==max)
r.push(a);
else
helper(a, i+1);
}
}
helper([], 0);
return r;
}
Usage:
cartesian([0,1], [0,1,2,3], [0,1,2]);
To make the function take an array of arrays, just change the signature to function cartesian(args) instead of using rest parameter syntax.
I suggest a simple recursive generator function:
// JS
function* cartesianIterator(head, ...tail) {
const remainder = tail.length ? cartesianIterator(...tail) : [[]];
for (let r of remainder) for (let h of head) yield [h, ...r];
}
// get values:
const cartesian = items => [...cartesianIterator(items)];
console.log(cartesian(input));
// TS
function* cartesianIterator<T>(items: T[][]): Generator<T[]> {
const remainder = items.length > 1 ? cartesianIterator(items.slice(1)) : [[]];
for (let r of remainder) for (let h of items.at(0)!) yield [h, ...r];
}
// get values:
const cartesian = <T>(items: T[][]) => [...cartesianIterator(items)];
console.log(cartesian(input));
You could take an iterative approach by building sub arrays.
var parts = [[0, 1], [0, 1, 2, 3], [0, 1, 2]],
result = parts.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []));
console.log(result.map(a => a.join(', ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
After doing a little research I discovered a previous related question:
Finding All Combinations of JavaScript array values
I've adapted some of the code from there so that it returns an array of arrays containing all of the permutations:
function(arraysToCombine) {
var divisors = [];
for (var i = arraysToCombine.length - 1; i >= 0; i--) {
divisors[i] = divisors[i + 1] ? divisors[i + 1] * arraysToCombine[i + 1].length : 1;
}
function getPermutation(n, arraysToCombine) {
var result = [],
curArray;
for (var i = 0; i < arraysToCombine.length; i++) {
curArray = arraysToCombine[i];
result.push(curArray[Math.floor(n / divisors[i]) % curArray.length]);
}
return result;
}
var numPerms = arraysToCombine[0].length;
for(var i = 1; i < arraysToCombine.length; i++) {
numPerms *= arraysToCombine[i].length;
}
var combinations = [];
for(var i = 0; i < numPerms; i++) {
combinations.push(getPermutation(i, arraysToCombine));
}
return combinations;
}
I've put a working copy at http://jsfiddle.net/7EakX/ that takes the array you gave earlier ([[0,1], [0,1,2,3], [0,1,2]]) and outputs the result to the browser console.
const charSet = [["A", "B"],["C", "D", "E"],["F", "G", "H", "I"]];
console.log(charSet.reduce((a,b)=>a.flatMap(x=>b.map(y=>x+y)),['']))
Just for fun, here's a more functional variant of the solution in my first answer:
function cartesian() {
var r = [], args = Array.from(arguments);
args.reduceRight(function(cont, factor, i) {
return function(arr) {
for (var j=0, l=factor.length; j<l; j++) {
var a = arr.slice(); // clone arr
a[i] = factor[j];
cont(a);
}
};
}, Array.prototype.push.bind(r))(new Array(args.length));
return r;
}
Alternative, for full speed we can dynamically compile our own loops:
function cartesian() {
return (cartesian.cache[arguments.length] || cartesian.compile(arguments.length)).apply(null, arguments);
}
cartesian.cache = [];
cartesian.compile = function compile(n) {
var args = [],
indent = "",
up = "",
down = "";
for (var i=0; i<n; i++) {
var arr = "$"+String.fromCharCode(97+i),
ind = String.fromCharCode(105+i);
args.push(arr);
up += indent+"for (var "+ind+"=0, l"+arr+"="+arr+".length; "+ind+"<l"+arr+"; "+ind+"++) {\n";
down = indent+"}\n"+down;
indent += " ";
up += indent+"arr["+i+"] = "+arr+"["+ind+"];\n";
}
var body = "var res=[],\n arr=[];\n"+up+indent+"res.push(arr.slice());\n"+down+"return res;";
return cartesian.cache[n] = new Function(args, body);
}
var f = function(arr){
if(typeof arr !== 'object'){
return false;
}
arr = arr.filter(function(elem){ return (elem !== null); }); // remove empty elements - make sure length is correct
var len = arr.length;
var nextPerm = function(){ // increase the counter(s)
var i = 0;
while(i < len)
{
arr[i].counter++;
if(arr[i].counter >= arr[i].length){
arr[i].counter = 0;
i++;
}else{
return false;
}
}
return true;
};
var getPerm = function(){ // get the current permutation
var perm_arr = [];
for(var i = 0; i < len; i++)
{
perm_arr.push(arr[i][arr[i].counter]);
}
return perm_arr;
};
var new_arr = [];
for(var i = 0; i < len; i++) // set up a counter property inside the arrays
{
arr[i].counter = 0;
}
while(true)
{
new_arr.push(getPerm()); // add current permutation to the new array
if(nextPerm() === true){ // get next permutation, if returns true, we got them all
break;
}
}
return new_arr;
};
Here's another way of doing it. I treat the indices of all of the arrays like a number whose digits are all different bases (like time and dates), using the length of the array as the radix.
So, using your first set of data, the first digit is base 2, the second is base 4, and the third is base 3. The counter starts 000, then goes 001, 002, then 010. The digits correspond to indices in the arrays, and since order is preserved, this is no problem.
I have a fiddle with it working here: http://jsfiddle.net/Rykus0/DS9Ea/1/
and here is the code:
// Arbitrary base x number class
var BaseX = function(initRadix){
this.radix = initRadix ? initRadix : 1;
this.value = 0;
this.increment = function(){
return( (this.value = (this.value + 1) % this.radix) === 0);
}
}
function combinations(input){
var output = [], // Array containing the resulting combinations
counters = [], // Array of counters corresponding to our input arrays
remainder = false, // Did adding one cause the previous digit to rollover?
temp; // Holds one combination to be pushed into the output array
// Initialize the counters
for( var i = input.length-1; i >= 0; i-- ){
counters.unshift(new BaseX(input[i].length));
}
// Get all possible combinations
// Loop through until the first counter rolls over
while( !remainder ){
temp = []; // Reset the temporary value collection array
remainder = true; // Always increment the last array counter
// Process each of the arrays
for( i = input.length-1; i >= 0; i-- ){
temp.unshift(input[i][counters[i].value]); // Add this array's value to the result
// If the counter to the right rolled over, increment this one.
if( remainder ){
remainder = counters[i].increment();
}
}
output.push(temp); // Collect the results.
}
return output;
}
// Input is an array of arrays
console.log(combinations([[0,1], [0,1,2,3], [0,1,2]]));
You can use a recursive function to get all combinations
const charSet = [["A", "B"],["C", "D", "E"],["F", "G", "H", "I"]];
let loopOver = (arr, str = '', final = []) => {
if (arr.length > 1) {
arr[0].forEach(v => loopOver(arr.slice(1), str + v, final))
} else {
arr[0].forEach(v => final.push(str + v))
}
return final
}
console.log(loopOver(charSet))
This code can still be shorten using ternary but i prefer the first version for readability 😊
const charSet = [["A", "B"],["C", "D", "E"],["F", "G", "H", "I"]];
let loopOver = (arr, str = '') => arr[0].map(v => arr.length > 1 ? loopOver(arr.slice(1), str + v) : str + v).flat()
console.log(loopOver(charSet))
Another implementation with ES6 recursive style
Array.prototype.cartesian = function(a,...as){
return a ? this.reduce((p,c) => (p.push(...a.cartesian(...as).map(e => as.length ? [c,...e] : [c,e])),p),[])
: this;
};
console.log(JSON.stringify([0,1].cartesian([0,1,2,3], [[0],[1],[2]])));

Categories