javascriptcombinationspermutationheaps-algorithm

Creating an array of all unique 4 digit numbers that can be made from the numbers 1-9 in JavaScript


I was set the task to create an array of all permutations/ 4 digit numbers of a given array of numbers: [1,2,3,4,5,6,7,8,9]. There can be no repeats of digits as each value must be unique. Below is my solution but I am struggling to apply recursion to the process. I want it to be adaptable so if conditions changed i.e. the function must produce all combinations of 5 digit numbers or even 6 digit, as little code needs to be changed and adding recursion would allow for this easily. As you can see below the code does work but if conditions changed this would require even more nested for loops. I am looking for a recursive solution. This does not seem like a good solution but any advice would be most grateful. I have seen a lot online about creating solutions where 4P4 or 5P5 but not 9P5 kind of styles. I tried to apply heap's algorithm but to no success.

function arrayCreate((availableNumbers, userNumberArray)) {

var possibleValues = []; //empty array to house all the possible combination of values that the user could enter i.e. 1234 to 9876
var numberOfPermutations = (factorial(availableNumbers.length) / factorial(availableNumbers.length - userNumberArray.length));

var adding = true;
var firstDigit, secondDigit, thirdDigit, forthDigit =0;
var possibleDigitValue = "";


while (adding === true) {
    for (var i = 0; i < availableNumbers.length; i++) {
        firstDigit = availableNumbers[i];
        availableNumbers.splice(i, 1);
        for (var j = 0; j < availableNumbers.length; j++) {
            secondDigit = availableNumbers[j];
            availableNumbers.splice(j, 1);
            for (var k = 0; k < availableNumbers.length; k++) {
                thirdDigit = availableNumbers[k]
                availableNumbers.splice(k, 1);
                for (var l = 0; l < availableNumbers.length; l++) {
                    forthDigit = availableNumbers[l];
                    possibleDigitValue = (firstDigit + secondDigit + thirdDigit + forthDigit);
                    possibleValues.push(possibleDigitValue);
                }
                availableNumbers.splice(k, 0, thirdDigit);
            }
            availableNumbers.splice(j, 0, secondDigit);
        }
        availableNumbers.splice(i, 0, firstDigit);
        if (possibleValues.length >= numberOfPermutations) {
            adding = false;
        }
    }
    console.log(possibleValues);
    return possibleValues;
}
}
arrayCreate([1,2,3,4,5,6,7,8,9],[0,0,0,0]);

var userNumberArray = ['0', '0', '0', '0']; //empty array of 0's as this value is not allowed, this array will store the computers auto-generated number
        var availableNumbers = ['1', '2', '3', '4', '5', '6', '7', '8', '9'] //array of available numbers to be picked and added to the computerNumber array
        


//this function is used later to calculate the possible permutations of combinations of user guess
function factorial(x) {
    if (x === 0) { return 1; }
    else{
        return x * factorial(x-1);
    }
}


function arrayCreate(availableNumbers, userNumberArray) {

    var possibleValues = []; //empty array to house all the possible combination of values that the user could enter i.e. 1234 to 9876
    var numberOfPermutations = (factorial(availableNumbers.length) / factorial(availableNumbers.length - userNumberArray.length));

    var adding = true;
    var firstDigit, secondDigit, thirdDigit, forthDigit =0;
    var possibleDigitValue = "";


    while (adding === true) {
        for (var i = 0; i < availableNumbers.length; i++) {
            firstDigit = availableNumbers[i];
            availableNumbers.splice(i, 1);
            for (var j = 0; j < availableNumbers.length; j++) {
                secondDigit = availableNumbers[j];
                availableNumbers.splice(j, 1);
                for (var k = 0; k < availableNumbers.length; k++) {
                    thirdDigit = availableNumbers[k]
                    availableNumbers.splice(k, 1);
                    for (var l = 0; l < availableNumbers.length; l++) {
                        forthDigit = availableNumbers[l];
                        possibleDigitValue = (firstDigit + secondDigit + thirdDigit + forthDigit);
                        possibleValues.push(possibleDigitValue);
                    }
                    availableNumbers.splice(k, 0, thirdDigit);
                }
                availableNumbers.splice(j, 0, secondDigit);
            }
            availableNumbers.splice(i, 0, firstDigit);
            if (possibleValues.length >= numberOfPermutations) {
                adding = false;
            }
        }
        return possibleValues;
    }
}
console.log(arrayCreate(availableNumbers, userNumberArray));


Solution

  • You could take a recursive approach by iterating the items and check if the item has been chosen before. If not then take that item and check the length of the part array.

    If that has the wanted length, puth the part array to the result.

    If not, iterate the given array and hand over the part array.

    function arrayCreate(array, size) {
        var result = [];
        array.forEach(function iter(parts) {
            return function (v) {
                var temp = parts.concat(v);
                if (parts.includes(v)) {
                    return;
                }
                if (temp.length === size) {
                    result.push(temp);
                    return;
                }
                array.forEach(iter(temp));
            }
        }([]));
        return result;
    }
    
    console.log(arrayCreate([1, 2, 3, 4, 5, 6, 7, 8, 9], 4).map(a => a.join('')));
    console.log(arrayCreate([1, 2, 3, 4, 5, 6, 7, 8, 9], 5).map(a => a.join('')));
    console.log(arrayCreate([1, 2, 3, 4, 5, 6, 7, 8, 9], 6).map(a => a.join('')));
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    With separated function iter.

    function arrayCreate(array, size) {
    
        function iter(parts) {
            return function (v) {
                var temp = parts.concat(v);
                if (parts.includes(v)) {
                    return;
                }
                if (temp.length === size) {
                    result.push(temp);
                    return;
                }
                array.forEach(iter(temp));
            }
        }
    
        var result = [];
        array.forEach(iter([]));
        return result;
    }
    
    console.log(arrayCreate([1, 2, 3, 4, 5, 6, 7, 8, 9], 4).map(a => a.join('')));
    console.log(arrayCreate([1, 2, 3, 4, 5, 6, 7, 8, 9], 5).map(a => a.join('')));
    console.log(arrayCreate([1, 2, 3, 4, 5, 6, 7, 8, 9], 6).map(a => a.join('')));
    .as-console-wrapper { max-height: 100% !important; top: 0; }