20

I'm a newbie to the JavaScript world. As the title mentions, I want to know whether there is any pre-built method in JavaScript to find all possible permutations of a given string.

For example, given the input:

the

Desired output:

the
teh
eht
eth
het
hte
Jason Plank
  • 2,336
  • 5
  • 31
  • 40
Ant's
  • 13,545
  • 27
  • 98
  • 148
  • 2
    When you say prebuilt, do you mean built-in? If so, the answer is No. – Felix Kling Mar 08 '11 at 12:18
  • +1 This is an interesting problem. it boils down to taking a set of elements and returning the set of all unique ordered sets build up of those elements. – Raynos Mar 08 '11 at 12:20
  • ya i say about built in function only! And i'm a very newbie to js, so say me any way to find that! – Ant's Mar 08 '11 at 12:28
  • @AntoAravinth There is no build in function. You have to write an algorithm. Then be really clever to get it round the O(n logn) speed. Also The function applied on the word "foobar" returns 720 results ;) "combinations" returns 479 million results – Raynos Mar 08 '11 at 12:31
  • @Raynos: i'm a newbie and its very difficult to solve this one for a newbie :) – Ant's Mar 08 '11 at 12:38
  • @Raynos, "foobar" has two 'o's and "combinations" has two 'o's, 'i's, and 'n's, so I imagine an acceptable function would return fewer results than you quote ^_~. – jswolf19 Mar 08 '11 at 12:48
  • @jswolf19 I think you'd still permute the discrete characters in the string, repeated or not. I think I posted an answer to a question essentially identical to this; I'll try to find it. – Pointy Mar 08 '11 at 12:51
  • OK [here](http://stackoverflow.com/questions/4431218/nested-for-loops-how-to-ignore-certain-combinations) is an old question I answered; this one uses arrays of numbers but doing it with strings of characters would be almost the same. – Pointy Mar 08 '11 at 12:54
  • @Pointy, true, the questioner doesn't use the word unique anywhere... I saw Raynos's use of the word and went with that when writing my comment. – jswolf19 Mar 08 '11 at 12:57
  • @all: ya it should be unique:) – Ant's Mar 08 '11 at 13:02
  • @jswolf19 why do you think that just because there are duplicates there are less results? Thanks @Pointy that's exactly what I was looking for. – Raynos Mar 08 '11 at 13:20
  • The real question is 'What are you trying to acheive?' - as there may be a better way to do it than generating all possible permuations of a given word. – belugabob Mar 08 '11 at 15:42
  • This similar question http://stackoverflow.com/questions/9960908/permutations-in-javascript has better answers. – le_m Jun 02 '16 at 16:28
  • Can you please unaccept my answer, so I can delete it? – Shadow The GPT Wizard Jun 03 '16 at 06:46

8 Answers8

21
//string permutation

function permutation(start, string) {

    //base case
    if ( string.length == 1 ) {
        return [ start + string ];
    } else {

        var returnResult = [];
        for (var i=0; i < string.length; i++) {
            var result = permutation (string[i], string.substr(0, i) + string.substr(i+1));
            for (var j=0; j<result.length; j++) {
                returnResult.push(start + result[j]);
            }
        }

        return returnResult;
    }
}

permutation('','123') will return

["123", "132", "213", "231", "312", "321"]

Henry Liu
  • 671
  • 1
  • 10
  • 19
  • This answer works correctly. Please make it the accepted one, OP. – le_m Jun 02 '16 at 16:26
  • 3
    It'd be even more usable if you swapped the parameters and added a `start = start || ""` line to guard against empty second parameter. That way you could just call it with `permutation('123')`. – mzywiol Apr 04 '17 at 11:06
5
function permutations(str){
  if (str.length === 1) {
      return str;
 }
  var permut = [];
  for (var i=0; i<str.length; i++){
      var s = str[0];
      var _new =  permutations(str.slice(1, str.length));
      for(var j=0; j<_new.length; j++) {
          permut.push(s + _new[j]);
      }
      str = str.substr(1, str.length -1) + s;
  }
  return permut;
}

permutations('the');
//output returns:[ 'the', 'teh', 'het', 'hte', 'eth', 'eht' ]

2

This is similar but finds all anagrams/permutations from an array of words. I had this question in an interview. Given an array of words ['cat', 'dog', 'tac', 'god', 'act'], return an array with all the anagrams grouped together. Makes sure the anagrams are unique.

var arr = ['cat', 'dog', 'tac', 'god', 'act'];

var allAnagrams = function(arr) {
    var anagrams = {};
    arr.forEach(function(str) {
        var recurse = function(ana, str) {
            if (str === '') 
                anagrams[ana] = 1;
            for (var i = 0; i < str.length; i++)
                recurse(ana + str[i], str.slice(0, i) + str.slice(i + 1));
        };
        recurse('', str);
    });
    return Object.keys(anagrams);
}

console.log(allAnagrams(arr));
//["cat", "cta", "act", "atc", "tca", "tac", "dog", "dgo", "odg", "ogd", "gdo", "god"]
Alex Hawkins
  • 616
  • 7
  • 10
2

No pre-built, but writing such function is possible.. here is one relatively simple way using two functions:

function FindAllPermutations(str, index, buffer) {
    if (typeof str == "string")
        str = str.split("");
    if (typeof index == "undefined")
        index = 0;
    if (typeof buffer == "undefined")
        buffer = [];
    if (index >= str.length)
        return buffer;
    for (var i = index; i < str.length; i++)
        buffer.push(ToggleLetters(str, index, i));
    return FindAllPermutations(str, index + 1, buffer);
}

function ToggleLetters(str, index1, index2) {
    if (index1 != index2) {
        var temp = str[index1];
        str[index1] = str[index2];
        str[index2] = temp;
    }
    return str.join("");
}

Usage:

var arrAllPermutations = FindAllPermutations("the");

Live test case: http://jsfiddle.net/yahavbr/X79vz/1/

This is just basic implementation, it won't remove duplicates and has no optimization. However for small strings you won't have any problem, add time measure like in the above test case and see what's your reasonable limit.

Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
  • 5
    -1 That's got to be broken. There are a countable number of outputs for `Hello World`. It should have 11! results. The string `hello wordl` is missing for example. – Raynos Mar 08 '11 at 13:18
  • @Raynos thanks for the heads up, improved version: http://jsfiddle.net/yahavbr/X79vz/3/ but still missing lots of permutations... still working on a complete fix. FTR, "hello world" should give back array with 39916800 items. – Shadow The GPT Wizard Mar 08 '11 at 13:36
  • but i dint understand anything with this function.. but anyways thanks :) – Ant's Mar 08 '11 at 13:41
  • @Shadow Better: `index = index || 0;` and `buffer = buffer || [];` – Šime Vidas Mar 08 '11 at 13:48
  • @Anto it will return correct results only for three letters strings.. for the rest it will return only partial results. You can still take some ideas from it though, feel free to ask for explanation about specific line in the code. – Shadow The GPT Wizard Mar 08 '11 at 13:58
  • @Shadow: in statements, you have used "undefined", it indicates that the user haven't passed any arguments for it! what happens if he does so? – Ant's Mar 08 '11 at 13:58
  • @Anto it's done so that user pass only the string and the function set those "private arguments" by itself. If user that call the function pass them manually it will make the function crash. – Shadow The GPT Wizard Mar 08 '11 at 14:03
  • @Shadow: ya exactly then whats there need? We can have only one function argument right? – Ant's Mar 08 '11 at 14:08
  • @Anto yes, like mentioned in the answer `FindAllPermutations("the")` will return array with 6 items which are the permutations. – Shadow The GPT Wizard Mar 08 '11 at 14:18
  • @Shadow: no my question is can we delete the other two arguments? I have done that, and passed only the word say "the", but i didnt get any answer, why so? – Ant's Mar 08 '11 at 14:45
  • Either fix this accepted answer or remove it, as it stands, it is flawed and has no real use to those with the same question, – le_m Jun 02 '16 at 16:20
  • @le_m I can't delete it even if I want to. I will try to see if I can fix it, and if not flag for moderator to remove it. Thanks for reminding me! – Shadow The GPT Wizard Jun 03 '16 at 06:43
  • @ShadowWizard not even for three letter strings. I just tried with "abc" and got a correct number of results (6), but two were duplicated: abc bac cab cab cba cba – mzywiol Apr 04 '17 at 11:00
1

Assuming a large string to search, you could use a regular expression

to examine a set of possibles that first matches the letters and the total number of letters,

and return the matches that use the same letter set as the pattern.

//(case-insensitive)

function lettersets(str, pat){
    var A= [], M, tem,
    rx= RegExp('\\b(['+pat+']{'+pat.length+'})\\b', 'gi'),
    pattern= pat.toLowerCase().split('').sort().join('');
    while((M= rx.exec(str))!= null){
        tem= M[1].toLowerCase().split('').sort();
        if(tem.join('')=== pattern) A.push(M[1]);
    };
    return A;
}

lettersets(s, 'the').sort();

kennebec
  • 102,654
  • 32
  • 106
  • 127
0
function swap(a, b, str) {
  if (a == b)
    str = str;

  else {
    str = str.split("");
    var temp = str[a];
    str[a] = str[b];
    str[b] = temp;
    str = str.join("");
  }
}

function anagram(a1, b1, ar) {
  if (a1 == b1)
    document.write(ar + "<br/>");

  else
    for (i = a1; i < b1; i++) {
      swap(a1, b1, ar);
      anagram((a1) ++, b1, ar);
      swap(a1, b1, ar);
    }
}
Jon Surrell
  • 9,444
  • 8
  • 48
  • 54
Yash
  • 1
0

Well there isnt any built in function in js(i dont believe it to be in any coding language)......and anyways this is the fully functioning program, it omits any repetitions and also displays the number of permutations.....

var n=0;
var counter=0;
var storarr=new Array();

function swap(a,b,str) {        //swaps the terms str[a] and str[b] and returns the final str
        str = str.split("");
        var temp = str[a];
        str[a] = str[b];
        str[b] = temp;
        return str.join("");
}

function anagram(_a,_b,ar) {        //actual function which produces the anagrams
    if(_a == _b) {
    storarr[n]=ar;
    n++;
    counter++;
    }
    else {
        for(var i= _a;i<= _b;i++) {
            ar=swap(_a,i,ar);
            anagram(_a+1,_b,ar);
            ar=swap(_a,i,ar);
        }
    }
}

function factorial(a) {         //return a!
    var x=1;
    for(var i=1;i<=a;i++)
    x=x*i;
    return x;
}

var strl=prompt("Enter String:","");
var l=strl.length;
anagram(0,l-1,strl);
storarr.sort();             //sorts the storarr alphabetically
var storlen=storarr.length;
var cai=0;
var counterarr = new Array();
strl.split("");

for(var i=0;i<l;i=i+c) {        //determines the number of times a term is repeating
    var c=1;
    for(var j=i+1;j<l;j++) {
        if(strl[i]==strl[j])
            c++;    
    }
    counterarr[cai]=c;
    cai++;
}

var yellow=1;

for(var i=0;i<counterarr.length;i++) {      //multiplies the terms of the counter array
    yellow=yellow*factorial(counterarr[i]);
}

counter=counter/yellow;
document.write("Count : " + counter + "<br />");

for(var i=0;i<storlen;i=i+yellow) {     //prints the non-flagged terms in storarr
    document.write(storarr[i] + "<br />");
}

strl.join("");
Yash
  • 1
-1
<pre>
<script>

var count = 0;
var duplicate = false;

function FindAllPermutations(str, index) {
    for (var i = index; i < str.length; i++) {
        var newstr;

        if (index == i) newstr = str;
            else newstr = SwapLetters(str, index, i);

        if (!duplicate) {
            count++;
            document.write(newstr + "\n");
            if (i == index) duplicate = true;
        } else if (i != index) duplicate = false;

        FindAllPermutations(newstr, index + 1);
      }
  }

function SwapLetters(str, index1, index2) {
    if (index1 == index2) return str;
    str = str.split("");
    var temp = str[index1];
    str[index1] = str[index2];
    str[index2] = temp;
    return str.join("");
}

FindAllPermutations("ABCD", 0); // will output all 24 permutations with no duplicates
document.write("Count: " + count);

</script>
Aaron Rox
  • 89
  • 1
  • 7