Эта версия использует довольно простую рекурсию:
const without = (n) => (xs) =>
[... xs .slice (0, n), ... xs .slice (n + 1)]
const permutations = (xs) =>
xs .length == 0
? []
: xs .length == 1
? [[xs[0]]]
: // else
xs .flatMap ((x, i) => permutations (without (i) (xs)) .map (p => [x, ...p]))
const stringPermutations = (s) => {
return permutations (s .split ('')) .map (ss => ss .join (''))
}
console .log (
stringPermutations ('abcd')
)
.as-console-wrapper {min-height: 100% !important; top: 0}
Существует вспомогательная функция without
, которая возвращает копию массива без заданного индекса. Например, without (2) (['a', 'b', 'c', 'd', 'e', 'f'])
дает ['a', 'b', 'd', 'e', 'f']
. Это используется только один раз внутри нашей основной функции и может быть легко встроено, но мне легче читать как есть.
stringPermutations
просто изменяет строку в массив односимвольных строк, вызывает permutations
и затем объединяет полученные массивы обратно в строки.
Важная часть - permutations
. Он имеет два базовых случая: когда входной массив пуст, он возвращает пустой массив. Когда он имеет только одно значение, он возвращает массив, содержащий массив, содержащий это значение. Во всех других случаях он выбирает каждый элемент по очереди для первого элемента, удаляя его из списка и рекурсивно вызывая permutations
с оставшимся списком для последующих позиций.