There is a code to search for anagrams, get an array of all anagrams, sort it and take an anagram index from an array that matches the source word. But there is a problem, for long words the code is very slow, maybe someone has already encountered such a problem? I will be glad to advice and help!

function listPosition(word) { var arr = [word]; 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); }); var result = Object.keys(anagrams); return result.sort().indexOf(word) + 1; } console.log(listPosition('BOOKKEEPER')); 
  • one
    Asking a question, provide input data, what happened with you and what is expected . - user207618
  • for large words, the script runs for a very long time, maybe there is some way to quickly create anagrams? - lesha310392
  • I repeat: the input ( 1, 2 ), your actions ( a + a + b ), the output you received ( 4 ) and the output you need ( 3 ). We can correct ( a + b ). - user207618
  • when called with 'BOOKKEEPER', the code runs for about 1.5 seconds, and if 'BOOKKEEPERMASTER' is executed for more than 10 seconds, is there any way to speed up the anagram creation process? - lesha310392
  • 2
    When building your anagrams, you essentially find all the permutations of the symbols of the word. And this is N! (N - word size in characters). For 5–120, for 10 it is already 3628800. It is clear that in this program you will convert the word into a number in this way, which will be unique for all possible words of a given size, composed of the same letters as this word. Most likely, to solve such a problem, some other approach is needed (taking a hash function?). By the way, what is the main task (knowing it, you can advise something adequate)? - avp

1 answer 1

First you need to learn how to count the total number of anagrams of a word.
Then you can recursively count the number of lexicographically smaller anagrams.

 const fact = n => n<2?n:n*fact(n-1); const wordletters = word => word.split('').sort() .reduce((res,letter) => (res[letter]=(res[letter]|0)+1, res), {}); const objVals = obj => Object.keys(obj) .map(key => obj[key]); // Общее число всех анаграмм // n! / (n₀!*n₁!*n₂!*...nₖ!) const anaCount = word => fact(word.length) / objVals(wordletters(word)) .map(fact) .reduce((c, a) => c*a, 1); const anaIndex = word => { let count = 0; let letters = Object.keys(wordletters(word)).sort(); let index = letters.indexOf(word[0]); let lesser = letters.slice(0, index); // буквы меньшие первой lesser.forEach(letter => { // Считаем все, начинающиеся на letter let set = word.split(''); // исключаем letter set.splice(set.indexOf(letter), 1); count += anaCount(set.join('')); }); // рекурсия от слова без первой буквы if (word.length > 1) count += anaIndex(word.substr(1)); return count; }; console.log(anaCount('BOOKKEEPER')); // 151200 console.log(anaIndex('BOOKKEEPER')); // 10742 console.log(anaIndex('BOOKKEEPERMASTER')); // 10991405956 

ES5

  • and if on ES6? thanks in advance! - lesha310392
  • In terms of es5? - vp_arth
  • Thank you very much! - lesha310392
  • But this does not solve the problem yet, only indicates the way) - vp_arth