Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I am looking for a review of my recursive function that generates the permutations of a string. Are there better ways to do this?

var permutations = [];

function doPerm(str, arr) {
    if (typeof (str) == 'string') str = str.split('');
    if (str.length == 0) permutations.push(arr.join(''));
    for (var i = 0; i < str.length; i++) {
        var x = str.splice(i, 1);
        arr.push(x);
        doPerm(str, arr);
        arr.pop();
        str.splice(i, 0, x);
    }
}
doPerm('', []);
console.log(permutations);
share|improve this question
1  
good code , no improvement needed as per this context –  paritosh Aug 10 '14 at 9:57
    
An implementation of Heap's algorithm in JavaScript (mentioned in @amon's answer) can be found here. –  mjolka Aug 10 '14 at 13:00
    
FYI, typeof is an operator, not a function. The parentheses around str are unnecessary and misleading. –  Ingo Bürk Aug 10 '14 at 13:55

2 Answers 2

up vote 3 down vote accepted

Your code seems to be correct, and is written in a good style. However, both the interface of your code as well as the algorithm used can be improved.

You currently have a global variable permutations which also contains the output. This variable will have to be cleared every time before doPerm is invoked. Instead, wrap doPerm in another function that provides initialization and input validation:

function perms(data) {
    if (!(data instanceof Array)) {
        throw new TypeError("input data must be an Array");
    }

    data = data.slice();  // make a copy
    var permutations = [],
        stack = [];

    function doPerm() {
        if (data.length == 0) {
            permutations.push(stack.slice());
        }
        for (var i = 0; i < data.length; i++) {
            var x = data.splice(i, 1);
            stack.push(x);
            doPerm();
            stack.pop();
            data.splice(i, 0, x);
        }
    }

    doPerm();
    return permutations;
}

var input = "abcd".split('');
var result = perms(input);
for (var i = 0; i < result.length; i++) {
    result[i] = result[i].join('');
}
console.log(result);

Note that this function will operate on arrays of any type and does not special-case strings.

Your algorithm currently relies on splicing elements into and out of the input array. This is somewhat expensive on larger data sets, and it would be better to generate the permutations by swapping. Heap's Algorithm does just this.

share|improve this answer
1  
Nice, although I'd recommend throwing a TypeError instead –  Flambino Aug 10 '14 at 11:06
3  
I think perms and doPerm are horrible names. Why not choose something meaningful? –  Ingo Bürk Aug 10 '14 at 13:55
2  
@IngoBürk quite right, doPerm could be improved – I'd probably use _perms or recurse in my own code. However, I do not see anything wrong with the name perms for a function that calculates permutations. There's a balance to be found between explicitness and terseness, and I think perms is a name that strikes a good balance when used for a local variable or method name. –  amon Aug 10 '14 at 14:29
1  
@amon Personally, I tend to be descriptive, so I'd probably write something like calculatePermutations. But even if one doesn't want to do that, I think abbreviating is unnecessary here. permutations would be simple and short, but expressive. I like recurse for the inner function's name. –  Ingo Bürk Aug 10 '14 at 15:06
    
great review, but why not replacing if (!(data instanceof Array)) { with if (!Array.isArray(data)) {? –  renatoargh Aug 10 '14 at 19:14

I modified your code after getting the error message: "too much recursion" for string of about 6 characters or so."

//====================================================
function getPermutations(str){
    //Enclosed data to be used by the internal recursive function permutate():
    var permutations = [],  //generated permutations stored here
        nextWord = [],      //next word builds up in here     
        chars = []          //collection for each recursion level
    ;
    //---------------------
    //split words or numbers into an array of characters
    if (typeof str === 'string') chars = str.split(''); 
    else if (typeof str === 'number') {
      str = str + ""; //convert number to string
      chars = str.split('');//convert string into char array
    }
    //============TWO Declaratives========
    permutate(chars);
    return permutations;
    //===========UNDER THE HOOD===========
    function permutate(chars){ //recursive: generates the permutations
        if(chars.length === 0)permutations.push(nextWord.join(''));            
        for (var i=0; i < chars.length; i++){
            chars.push(chars.shift());  //rotate the characters
            nextWord.push(chars[0]);    //use the first char in the array            
            permutate(chars.slice(1));  //Recurse: array-less-one-char
            nextWord.pop();             //clear for nextWord (multiple pops)
        }
    }
    //--------------------------------
}//==============END of getPermutations(str)=============

Some of the names are long, but descriptive.

Features:

  1. No longer get the "too much recursion" message.
  2. Only one argument is passed to the function.
  3. Takes a string or a number argument.
  4. Variables are not global but enclosed in the outer function.
  5. The inner function does the recursion using closure variables
  6. Doesn't use splice, but uses slice only once.

Anything else you can add of value or take away would be appreciated.

share|improve this answer
    
Welcome to CodeReview, Sabba. I hope you enjoy the site. –  Legato Jul 20 at 3:49
    
Thanks. Looking forward to it! –  Sabba Kilam Jul 22 at 2:49

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.