w3schools tag tab style page for color javascript permutation

javascript - tag - title of page html



Permutaciones en JavaScript? (23)

Intento escribir una función que haga lo siguiente:

  • toma una matriz de enteros como argumento (ej. [1,2,3,4])
  • crea una matriz de todas las permutaciones posibles de [1,2,3,4], con cada permutación que tiene una longitud de 4

la función a continuación (la encontré en línea) hace esto tomando una cadena como argumento y devolviendo todas las permutaciones de esa cadena

No pude encontrar la manera de modificarlo para que funcione con una matriz de enteros (creo que esto tiene algo que ver con la forma en que algunos de los métodos funcionan de forma diferente en las cadenas que en los enteros, pero no estoy seguro). ..)

var permArr = [], usedChars = []; function permute(input) { var i, ch, chars = input.split(""); for (i = 0; i < chars.length; i++) { ch = chars.splice(i, 1); usedChars.push(ch); if (chars.length == 0) permArr[permArr.length] = usedChars.join(""); permute(chars.join("")); chars.splice(i, 0, ch); usedChars.pop(); } return permArr };

Nota: Estoy buscando hacer que la función devuelva matrices de enteros , no una matriz de cadenas .

Realmente necesito la solución para estar en JavaScript. Ya he descubierto cómo hacerlo en Python


Alguna versión inspirada de Haskell:

perms [] = [[]] perms xs = [ x:ps | x <- xs , ps <- perms ( xs//[x] ) ]

function perms(xs){ if (!xs.length) return [[]]; var r=[]; for (var i=0;i<xs.length;i++){ var xs_ = xs.slice(), x = xs_.splice(i, 1), ps = perms(xs_); r.push(...ps.map(p=>x.concat(p))) } return r; } document.write(JSON.stringify(perms([1,2,3])));


Aquí hay otra solución "más recursiva".

function perms(input) { var data = input.slice(); var permutations = []; var n = data.length; if (n === 0) { return [ [] ]; } else { var first = data.shift(); var words = perms(data); words.forEach(function(word) { for (var i = 0; i < n; ++i) { var tmp = word.slice(); tmp.splice(i, 0, first) permutations.push(tmp); } }); } return permutations; } var str = ''ABC''; var chars = str.split(''''); var result = perms(chars).map(function(p) { return p.join(''''); }); console.log(result);

Salida:

[ ''ABC'', ''BAC'', ''BCA'', ''ACB'', ''CAB'', ''CBA'' ]


De espíritu similar a la solución al estilo Haskell de @crl, pero trabajando con reduce :

function permutations( base ) { if (base.length == 0) return [[]] return permutations( base.slice(1) ).reduce( function(acc,perm) { return acc.concat( base.map( function(e,pos) { var new_perm = perm.slice() new_perm.splice(pos,0,base[0]) return new_perm })) },[]) }


El siguiente algoritmo muy eficiente usa el método de Heap para generar todas las permutaciones de N elementos con complejidad de tiempo de ejecución en O (N!):

function permute(permutation) { var length = permutation.length, result = [permutation.slice()], c = new Array(length).fill(0), i = 1, k, p; while (i < length) { if (c[i] < i) { k = i % 2 && c[i]; p = permutation[i]; permutation[i] = permutation[k]; permutation[k] = p; ++c[i]; i = 1; result.push(permutation.slice()); } else { c[i] = 0; ++i; } } return result; } console.log(permute([1, 2, 3]));

El mismo algoritmo implementado como generator con complejidad de espacio en O (N):

function* permute(permutation) { var length = permutation.length, c = Array(length).fill(0), i = 1, k, p; yield permutation.slice(); while (i < length) { if (c[i] < i) { k = i % 2 && c[i]; p = permutation[i]; permutation[i] = permutation[k]; permutation[k] = p; ++c[i]; i = 1; yield permutation.slice(); } else { c[i] = 0; ++i; } } } // Memory efficient iteration through permutations: for (var permutation of permute([1, 2, 3])) console.log(permutation); // Simple array conversion: var permutations = [...permute([1, 2, 3])];

Comparación de rendimiento

Siéntase libre de agregar su implementación al siguiente banco de pruebas benchmark.js :

function permute_SiGanteng(input) { var permArr = [], usedChars = []; function permute(input) { var i, ch; for (i = 0; i < input.length; i++) { ch = input.splice(i, 1)[0]; usedChars.push(ch); if (input.length == 0) { permArr.push(usedChars.slice()); } permute(input); input.splice(i, 0, ch); usedChars.pop(); } return permArr } return permute(input); } function permute_delimited(inputArr) { var results = []; function permute(arr, memo) { var cur, memo = memo || []; for (var i = 0; i < arr.length; i++) { cur = arr.splice(i, 1); if (arr.length === 0) { results.push(memo.concat(cur)); } permute(arr.slice(), memo.concat(cur)); arr.splice(i, 0, cur[0]); } return results; } return permute(inputArr); } function permute_monkey(inputArray) { return inputArray.reduce(function permute(res, item, key, arr) { return res.concat(arr.length > 1 && arr.slice(0, key).concat(arr.slice(key + 1)).reduce(permute, []).map(function(perm) { return [item].concat(perm); }) || item); }, []); } function permute_Oriol(input) { var permArr = [], usedChars = []; return (function main() { for (var i = 0; i < input.length; i++) { var ch = input.splice(i, 1)[0]; usedChars.push(ch); if (input.length == 0) { permArr.push(usedChars.slice()); } main(); input.splice(i, 0, ch); usedChars.pop(); } return permArr; })(); } function permute_MarkusT(input) { function permutate(array, callback) { function p(array, index, callback) { function swap(a, i1, i2) { var t = a[i1]; a[i1] = a[i2]; a[i2] = t; } if (index == array.length - 1) { callback(array); return 1; } else { var count = p(array, index + 1, callback); for (var i = index + 1; i < array.length; i++) { swap(array, i, index); count += p(array, index + 1, callback); swap(array, i, index); } return count; } } if (!array || array.length == 0) { return 0; } return p(array, 0, callback); } var result = []; permutate(input, function(a) { result.push(a.slice(0)); }); return result; } function permute_le_m(permutation) { var length = permutation.length, result = [permutation.slice()], c = new Array(length).fill(0), i = 1, k, p; while (i < length) { if (c[i] < i) { k = i % 2 && c[i], p = permutation[i]; permutation[i] = permutation[k]; permutation[k] = p; ++c[i]; i = 1; result.push(permutation.slice()); } else { c[i] = 0; ++i; } } return result; } function permute_Urielzen(arr) { var finalArr = []; var iterator = function (arrayTaken, tree) { for (var i = 0; i < tree; i++) { var temp = arrayTaken.slice(); temp.splice(tree - 1 - i, 0, temp.splice(tree - 1, 1)[0]); if (tree >= arr.length) { finalArr.push(temp); } else { iterator(temp, tree + 1); } } } iterator(arr, 1); return finalArr; } function permute_Taylor_Hakes(arr) { var permutations = []; if (arr.length === 1) { return [ arr ]; } for (var i = 0; i < arr.length; i++) { var subPerms = permute_Taylor_Hakes(arr.slice(0, i).concat(arr.slice(i + 1))); for (var j = 0; j < subPerms.length; j++) { subPerms[j].unshift(arr[i]); permutations.push(subPerms[j]); } } return permutations; } var Combinatorics = (function () { ''use strict''; var version = "0.5.2"; /* combinatory arithmetics */ var P = function(m, n) { var p = 1; while (n--) p *= m--; return p; }; var C = function(m, n) { if (n > m) { return 0; } return P(m, n) / P(n, n); }; var factorial = function(n) { return P(n, n); }; var factoradic = function(n, d) { var f = 1; if (!d) { for (d = 1; f < n; f *= ++d); if (f > n) f /= d--; } else { f = factorial(d); } var result = [0]; for (; d; f /= d--) { result[d] = Math.floor(n / f); n %= f; } return result; }; /* common methods */ var addProperties = function(dst, src) { Object.keys(src).forEach(function(p) { Object.defineProperty(dst, p, { value: src[p], configurable: p == ''next'' }); }); }; var hideProperty = function(o, p) { Object.defineProperty(o, p, { writable: true }); }; var toArray = function(f) { var e, result = []; this.init(); while (e = this.next()) result.push(f ? f(e) : e); this.init(); return result; }; var common = { toArray: toArray, map: toArray, forEach: function(f) { var e; this.init(); while (e = this.next()) f(e); this.init(); }, filter: function(f) { var e, result = []; this.init(); while (e = this.next()) if (f(e)) result.push(e); this.init(); return result; }, lazyMap: function(f) { this._lazyMap = f; return this; }, lazyFilter: function(f) { Object.defineProperty(this, ''next'', { writable: true }); if (typeof f !== ''function'') { this.next = this._next; } else { if (typeof (this._next) !== ''function'') { this._next = this.next; } var _next = this._next.bind(this); this.next = (function() { var e; while (e = _next()) { if (f(e)) return e; } return e; }).bind(this); } Object.defineProperty(this, ''next'', { writable: false }); return this; } }; /* power set */ var power = function(ary, fun) { var size = 1 << ary.length, sizeOf = function() { return size; }, that = Object.create(ary.slice(), { length: { get: sizeOf } }); hideProperty(that, ''index''); addProperties(that, { valueOf: sizeOf, init: function() { that.index = 0; }, nth: function(n) { if (n >= size) return; var i = 0, result = []; for (; n; n >>>= 1, i++) if (n & 1) result.push(this[i]); return (typeof (that._lazyMap) === ''function'')?that._lazyMap(result):result; }, next: function() { return this.nth(this.index++); } }); addProperties(that, common); that.init(); return (typeof (fun) === ''function'') ? that.map(fun) : that; }; /* combination */ var nextIndex = function(n) { var smallest = n & -n, ripple = n + smallest, new_smallest = ripple & -ripple, ones = ((new_smallest / smallest) >> 1) - 1; return ripple | ones; }; var combination = function(ary, nelem, fun) { if (!nelem) nelem = ary.length; if (nelem < 1) throw new RangeError; if (nelem > ary.length) throw new RangeError; var first = (1 << nelem) - 1, size = C(ary.length, nelem), maxIndex = 1 << ary.length, sizeOf = function() { return size; }, that = Object.create(ary.slice(), { length: { get: sizeOf } }); hideProperty(that, ''index''); addProperties(that, { valueOf: sizeOf, init: function() { this.index = first; }, next: function() { if (this.index >= maxIndex) return; var i = 0, n = this.index, result = []; for (; n; n >>>= 1, i++) { if (n & 1) result[result.length] = this[i]; } this.index = nextIndex(this.index); return (typeof (that._lazyMap) === ''function'')?that._lazyMap(result):result; } }); addProperties(that, common); that.init(); return (typeof (fun) === ''function'') ? that.map(fun) : that; }; /* permutation */ var _permutation = function(ary) { var that = ary.slice(), size = factorial(that.length); that.index = 0; that.next = function() { if (this.index >= size) return; var copy = this.slice(), digits = factoradic(this.index, this.length), result = [], i = this.length - 1; for (; i >= 0; --i) result.push(copy.splice(digits[i], 1)[0]); this.index++; return (typeof (that._lazyMap) === ''function'')?that._lazyMap(result):result; }; return that; }; // which is really a permutation of combination var permutation = function(ary, nelem, fun) { if (!nelem) nelem = ary.length; if (nelem < 1) throw new RangeError; if (nelem > ary.length) throw new RangeError; var size = P(ary.length, nelem), sizeOf = function() { return size; }, that = Object.create(ary.slice(), { length: { get: sizeOf } }); hideProperty(that, ''cmb''); hideProperty(that, ''per''); addProperties(that, { valueOf: function() { return size; }, init: function() { this.cmb = combination(ary, nelem); this.per = _permutation(this.cmb.next()); }, next: function() { var result = this.per.next(); if (!result) { var cmb = this.cmb.next(); if (!cmb) return; this.per = _permutation(cmb); return this.next(); } return (typeof (that._lazyMap) === ''function'')?that._lazyMap(result):result; } }); addProperties(that, common); that.init(); return (typeof (fun) === ''function'') ? that.map(fun) : that; }; /* export */ var Combinatorics = Object.create(null); addProperties(Combinatorics, { C: C, P: P, factorial: factorial, factoradic: factoradic, permutation: permutation, }); return Combinatorics; })(); var suite = new Benchmark.Suite; var input = [0, 1, 2, 3, 4]; suite.add(''permute_SiGanteng'', function() { permute_SiGanteng(input); }) .add(''permute_delimited'', function() { permute_delimited(input); }) .add(''permute_monkey'', function() { permute_monkey(input); }) .add(''permute_Oriol'', function() { permute_Oriol(input); }) .add(''permute_MarkusT'', function() { permute_MarkusT(input); }) .add(''permute_le_m'', function() { permute_le_m(input); }) .add(''permute_Urielzen'', function() { permute_Urielzen(input); }) .add(''permute_Taylor_Hakes'', function() { permute_Taylor_Hakes(input); }) .add(''permute_Combinatorics'', function() { Combinatorics.permutation(input).toArray(); }) .on(''cycle'', function(event) { console.log(String(event.target)); }) .on(''complete'', function() { console.log(''Fastest is '' + this.filter(''fastest'').map(''name'')); }) .run({async: true});

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.4/platform.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.4/benchmark.min.js"></script>

Resultados en tiempo de ejecución para Chrome 48:

  • 99.152 ms Este algoritmo
  • 153.115ms MarkusT
  • 401.255ms js-combinatorics
  • 497.037ms Urielzen
  • 925.669 ms Oriol
  • 1026.571ms SiGanteng
  • 2529.841ms delimited
  • 3992.622ms monkey
  • 4514.665ms Oriol

Escribí una post para demostrar cómo permutar una matriz en JavaScript. Aquí está el código que hace esto.

var count=0; function permute(pre,cur){ var len=cur.length; for(var i=0;i<len;i++){ var p=clone(pre); var c=clone(cur); p.push(cur[i]); remove(c,cur[i]); if(len>1){ permute(p,c); }else{ print(p); count++; } } } function print(arr){ var len=arr.length; for(var i=0;i<len;i++){ document.write(arr[i]+" "); } document.write("<br />"); } function remove(arr,item){ if(contains(arr,item)){ var len=arr.length; for(var i = len-1; i >= 0; i--){ // STEP 1 if(arr[i] == item){ // STEP 2 arr.splice(i,1); // STEP 3 } } } } function contains(arr,value){ for(var i=0;i<arr.length;i++){ if(arr[i]==value){ return true; } } return false; } function clone(arr){ var a=new Array(); var len=arr.length; for(var i=0;i<len;i++){ a.push(arr[i]); } return a; }

Solo llama

permutar ([], [1,2,3,4])

trabajará. Para obtener detalles sobre cómo funciona esto, consulte la explicación en esa publicación.


Esta es una tarea interesante y esta es mi contribución. Es muy simple y rápido. Si está interesado, por favor tengan paciencia conmigo y sigan leyendo.

Si desea realizar este trabajo rápidamente, definitivamente debe ingresar a la programación dinámica. Lo que significa que debes olvidarte de los enfoques recursivos. Eso es seguro...

El código de OK le_m que usa el método del Heap parece ser el más rápido hasta ahora. Bueno, no tengo un nombre para mi algoritmo, no sé si ya se ha implementado o no, pero es muy simple y rápido. Como con todos los enfoques de programación dinámica, comenzaremos por el problema más simple y buscaremos el resultado final.

Suponiendo que tenemos una matriz de a = [1,2,3] comenzaremos con

r = [[1]]; // result t = []; // interim result

Luego sigue estos tres pasos;

  1. Para cada elemento de nuestra matriz r (resultado), agregaremos el siguiente elemento de la matriz de entrada.
  2. Rotaremos cada artículo su longitud muchas veces y almacenaremos cada instancia en el conjunto de resultados provisional t . (Bueno, excepto el primero que no pierde el tiempo con la rotación 0)
  3. Una vez que terminamos con todos los ítems de r la matriz interina t debe contener el siguiente nivel de resultados, por lo que hacemos r = t; t = []; r = t; t = []; y continuar hasta la longitud de la matriz de entrada a .

Entonces los siguientes son nuestros pasos;

r array t array [[1,2]] [[1,2], [2,1]] [[1,2],[2,1]] [[1,2,3],[2,3,1],[3,1,2], [2,1,3],[1,3,2],[3,2,1]]

Así que aquí está el código

function perm(a){ var r = [[a[0]]], t = [], s = []; if (a.length <= 1) return a; for (var i = 1, la = a.length; i < la; i++){ for (var j = 0, lr = r.length; j < lr; j++){ r[j].push(a[i]); t.push(r[j]); for(var k = 1, lrj = r[j].length; k < lrj; k++){ for (var l = 0; l < lrj; l++) s[l] = r[j][(k+l)%lrj]; t[t.length] = s; s = []; } } r = t; t = []; } return r; } var arr = [0,1,2,4,5]; console.log("The length of the permutation is:",perm(arr).length); console.time("Permutation test"); for (var z = 0; z < 2000; z++) perm(arr); console.timeEnd("Permutation test");

En pruebas múltiples lo he visto resolviendo las 120 permutaciones de [0,1,2,3,4] durante 2000 veces en 25 ~ 35 ms.


He mejorado la answer SiGanteng .

Ahora es posible llamar al permute más de una vez, ya que permArr y usedChars se borran cada vez.

function permute(input) { var permArr = [], usedChars = []; return (function main() { for (var i = 0; i < input.length; i++) { var ch = input.splice(i, 1)[0]; usedChars.push(ch); if (input.length == 0) { permArr.push(usedChars.slice()); } main(); input.splice(i, 0, ch); usedChars.pop(); } return permArr; })(); }

function permute(input) { var permArr = [], usedChars = []; return (function main() { for (var i = 0; i < input.length; i++) { var ch = input.splice(i, 1)[0]; usedChars.push(ch); if (input.length == 0) { permArr.push(usedChars.slice()); } main(); input.splice(i, 0, ch); usedChars.pop(); } return permArr; })(); } document.write(JSON.stringify(permute([5, 3, 7, 1])));


La mayoría de las otras respuestas no utilizan las nuevas funciones del generador de JavaScript, que es una solución perfecta para este tipo de problema. Probablemente solo necesites una permutación al momento en la memoria. Además, prefiero generar una permutación de un rango de índices ya que esto me permite indexar cada permutación y saltar directamente a cualquier permutación en particular, así como también ser utilizado para permutar cualquier otra colección.

// ES6 generator version of python itertools [permutations and combinations] const range = function*(l) { for (let i = 0; i < l; i+=1) yield i; } const isEmpty = arr => arr.length === 0; const permutations = function*(a) { const r = arguments[1] || []; if (isEmpty(a)) yield r; for (let i of range(a.length)) { const aa = [...a]; const rr = [...r, ...aa.splice(i, 1)]; yield* permutations(aa, rr); } } console.log(''permutations of ABC''); console.log(JSON.stringify([...permutations([...''ABC''])])); const combinations = function*(a, count) { const r = arguments[2] || []; if (count) { count = count - 1; for (let i of range(a.length - count)) { const aa = a.slice(i); const rr = [...r, ...aa.splice(0, 1)]; yield* combinations(aa, count, rr); } } else { yield r; } } console.log(''combinations of 2 of ABC''); console.log(JSON.stringify([...combinations([...''ABC''], 2)])); const permutator = function() { const range = function*(args) { let {begin = 0, count} = args; for (let i = begin; count; count--, i+=1) { yield i; } } const factorial = fact => fact ? fact * factorial(fact - 1) : 1; return { perm: function(n, permutationId) { const indexCount = factorial(n); permutationId = ((permutationId%indexCount)+indexCount)%indexCount; let permutation = [0]; for (const choiceCount of range({begin: 2, count: n-1})) { const choice = permutationId % choiceCount; const lastIndex = permutation.length; permutation.push(choice); permutation = permutation.map((cv, i, orig) => (cv < choice || i == lastIndex) ? cv : cv + 1 ); permutationId = Math.floor(permutationId / choiceCount); } return permutation.reverse(); }, perms: function*(n) { for (let i of range({count: factorial(n)})) { yield this.perm(n, i); } } }; }(); console.log(''indexing type permutator''); let i = 0; for (let elem of permutator.perms(3)) { console.log(`${i}: ${elem}`); i+=1; } console.log(); console.log(`3: ${permutator.perm(3,3)}`);


La mayoría de las respuestas a esta pregunta utilizan operaciones costosas, como inserciones continuas y eliminaciones de elementos en una matriz, o copia de matrices reiterativamente.

En cambio, esta es la solución típica de retroceso:

function permute(arr) { var results = [], l = arr.length, used = Array(l), // Array of bools. Keeps track of used items data = Array(l); // Stores items of the current permutation (function backtracking(pos) { if(pos == l) return results.push(data.slice()); for(var i=0; i<l; ++i) if(!used[i]) { // Iterate unused items used[i] = true; // Mark item as used data[pos] = arr[i]; // Assign item at the current position backtracking(pos+1); // Recursive call used[i] = false; // Mark item as not used } })(0); return results; }

permute([1,2,3,4]); // [ [1,2,3,4], [1,2,4,3], /* ... , */ [4,3,2,1] ]

Dado que la matriz de resultados será enorme, podría ser una buena idea iterar los resultados uno por uno en lugar de asignar todos los datos simultáneamente. En ES6, esto se puede hacer con generadores:

function permute(arr) { var l = arr.length, used = Array(l), data = Array(l); return function* backtracking(pos) { if(pos == l) yield data.slice(); else for(var i=0; i<l; ++i) if(!used[i]) { used[i] = true; data[pos] = arr[i]; yield* backtracking(pos+1); used[i] = false; } }(0); }

var p = permute([1,2,3,4]); p.next(); // {value: [1,2,3,4], done: false} p.next(); // {value: [1,2,4,3], done: false} // ... p.next(); // {value: [4,3,2,1], done: false} p.next(); // {value: undefined, done: true}


La siguiente función permuta una matriz de cualquier tipo y llama a una función de devolución de llamada especificada en cada permutación encontrada:

/* Permutate the elements in the specified array by swapping them in-place and calling the specified callback function on the array for each permutation. Return the number of permutations. If array is undefined, null or empty, return 0. NOTE: when permutation succeeds, the array should be in the original state on exit! */ function permutate(array, callback) { // Do the actual permuation work on array[], starting at index function p(array, index, callback) { // Swap elements i1 and i2 in array a[] function swap(a, i1, i2) { var t = a[i1]; a[i1] = a[i2]; a[i2] = t; } if (index == array.length - 1) { callback(array); return 1; } else { var count = p(array, index + 1, callback); for (var i = index + 1; i < array.length; i++) { swap(array, i, index); count += p(array, index + 1, callback); swap(array, i, index); } return count; } } if (!array || array.length == 0) { return 0; } return p(array, 0, callback); }

Si lo llamas así:

// Empty array to hold results var result = []; // Permutate [1, 2, 3], pushing every permutation onto result[] permutate([1, 2, 3], function (a) { // Create a copy of a[] and add that to result[] result.push(a.slice(0)); }); // Show result[] document.write(result);

Creo que hará exactamente lo que necesita: complete una matriz llamada result con las permutaciones de la matriz [1, 2, 3]. El resultado es:

[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,2,1],[3,1,2]]

Código ligeramente más claro en JSFiddle: http://jsfiddle.net/MgmMg/6/


Mi primera contribución al sitio. Vea here algunos dibujos explicativos del algoritmo detrás del código. Además, de acuerdo con las pruebas que he hecho, este código se ejecuta más rápido que todos los otros métodos mencionados aquí antes de esta fecha, por supuesto es mínimo si hay pocos valores, pero el tiempo aumenta exponencialmente cuando se agregan demasiados.

var permutations2 = function (arr) { var finalArr = []; var iterator = function (arrayTaken, tree) { for (var i = 0; i < tree; i++) { var temp = arrayTaken.slice(); temp.splice(tree - 1 - i, 0, temp.splice(tree - 1, 1)[0]); if (tree >= arr.length) { finalArr.push(temp); } else { iterator(temp, tree + 1); } } } iterator(arr, 1); return finalArr; };


Poco tarde, pero me gusta agregar una versión un poco más elegante aquí. Puede ser cualquier matriz ...

function permutator(inputArr) { var results = []; function permute(arr, memo) { var cur, memo = memo || []; for (var i = 0; i < arr.length; i++) { cur = arr.splice(i, 1); if (arr.length === 0) { results.push(memo.concat(cur)); } permute(arr.slice(), memo.concat(cur)); arr.splice(i, 0, cur[0]); } return results; } return permute(inputArr); }

Agregar una versión ES6 (2015). Además, no muta la matriz de entrada original. Funciona en la consola en Chrome ...

const permutator = (inputArr) => { let result = []; const permute = (arr, m = []) => { if (arr.length === 0) { result.push(m) } else { for (let i = 0; i < arr.length; i++) { let curr = arr.slice(); let next = curr.splice(i, 1); permute(curr.slice(), m.concat(next)) } } } permute(inputArr) return result; }

Asi que...

permutator([''c'',''a'',''t'']);

Rinde ...

[ [ ''c'', ''a'', ''t'' ], [ ''c'', ''t'', ''a'' ], [ ''a'', ''c'', ''t'' ], [ ''a'', ''t'', ''c'' ], [ ''t'', ''c'', ''a'' ], [ ''t'', ''a'', ''c'' ] ]

Y...

permutator([1,2,3]);

Rinde ...

[ [ 1, 2, 3 ], [ 1, 3, 2 ], [ 2, 1, 3 ], [ 2, 3, 1 ], [ 3, 1, 2 ], [ 3, 2, 1 ] ]


Responde sin la necesidad de una matriz exterior o función adicional

function permutator (arr) { var permutations = []; if (arr.length === 1) { return [ arr ]; } for (var i = 0; i < arr.length; i++) { var subPerms = permutator(arr.slice(0, i).concat(arr.slice(i + 1))); for (var j = 0; j < subPerms.length; j++) { subPerms[j].unshift(arr[i]); permutations.push(subPerms[j]); } } return permutations; }


Si se da cuenta, el código realmente divide los caracteres en una matriz antes de realizar cualquier permutación, por lo que simplemente elimina la operación de unión y división

var permArr = [], usedChars = []; function permute(input) { var i, ch; for (i = 0; i < input.length; i++) { ch = input.splice(i, 1)[0]; usedChars.push(ch); if (input.length == 0) { permArr.push(usedChars.slice()); } permute(input); input.splice(i, 0, ch); usedChars.pop(); } return permArr }; document.write(JSON.stringify(permute([5, 3, 7, 1])));


This is a very nice use-case for map/reduce:

function permutations(arr) { return (arr.length === 1) ? arr : arr.reduce((acc, cv, index) => { let remaining = [...arr]; remaining.splice(index, 1); return acc.concat(permutations(remaining).map(a => [].concat(cv,a))); }, []); }

  • First, we handle the base case and simply return the array if there is only on item in it
  • In all other cases
    • we create an empty array
    • loop over the input-array
    • and add an array of the current value and all permutations of the remaining array [].concat(cv,a)

"use strict"; function getPermutations(arrP) { var results = []; var arr = arrP; arr.unshift(null); var length = arr.length; while (arr[0] === null) { results.push(arr.slice(1).join('''')); let less = null; let lessIndex = null; for (let i = length - 1; i > 0; i--) { if(arr[i - 1] < arr[i]){ less = arr[i - 1]; lessIndex = i - 1; break; } } for (let i = length - 1; i > lessIndex; i--) { if(arr[i] > less){ arr[lessIndex] = arr[i]; arr[i] = less; break; } } for(let i = lessIndex + 1; i<length; i++){ for(let j = i + 1; j < length; j++){ if(arr[i] > arr[j] ){ arr[i] = arr[i] + arr[j]; arr[j] = arr[i] - arr[j]; arr[i] = arr[i] - arr[j]; } } } } return results; } var res = getPermutations([1,2,3,4,5]); var out = document.getElementById(''myTxtArr''); res.forEach(function(i){ out.value+=i+'', ''});

textarea{ height:500px; width:500px; }

<textarea id=''myTxtArr''></textarea>

Outputs lexicographically ordered permutations. Works only with numbers. In other case, you have to change the swap method on line 34.


Aquí hay una solución muy corta, que solo funciona para 1 o 2 cadenas largas. Es un oneliner, y es increíblemente rápido, usa ES6 y no depende de jQuery. Disfrutar:

var p = l => l.length<2 ? [l] : l.length==2 ? [l[0]+l[1],l[1]+l[0]] : Function(''throw Error("unimplemented")'')();


function perm(xs) { return xs.length === 0 ? [[]] : perm(xs.slice(1)).reduce(function (acc, ys) { for (var i = 0; i < xs.length; i++) { acc.push([].concat(ys.slice(0, i), xs[0], ys.slice(i))); } return acc; }, []); }

Pruébalo con:

console.log(JSON.stringify(perm([1, 2, 3,4])));


let permutations = [] permutate([], { color: [''red'', ''green''], size: [''big'', ''small'', ''medium''], type: [''saison'', ''oldtimer''] }) function permutate (currentVals, remainingAttrs) { remainingAttrs[Object.keys(remainingAttrs)[0]].forEach(attrVal => { let currentValsNew = currentVals.slice(0) currentValsNew.push(attrVal) if (Object.keys(remainingAttrs).length > 1) { let remainingAttrsNew = JSON.parse(JSON.stringify(remainingAttrs)) delete remainingAttrsNew[Object.keys(remainingAttrs)[0]] permutate(currentValsNew, remainingAttrsNew) } else { permutations.push(currentValsNew) } }) }

Resultado:

[ [ ''red'', ''big'', ''saison'' ], [ ''red'', ''big'', ''oldtimer'' ], [ ''red'', ''small'', ''saison'' ], [ ''red'', ''small'', ''oldtimer'' ], [ ''red'', ''medium'', ''saison'' ], [ ''red'', ''medium'', ''oldtimer'' ], [ ''green'', ''big'', ''saison'' ], [ ''green'', ''big'', ''oldtimer'' ], [ ''green'', ''small'', ''saison'' ], [ ''green'', ''small'', ''oldtimer'' ], [ ''green'', ''medium'', ''saison'' ], [ ''green'', ''medium'', ''oldtimer'' ] ]


#!/usr/bin/env node "use strict"; function perm(arr) { if(arr.length<2) return [arr]; var res = []; arr.forEach(function(x, i) { perm(arr.slice(0,i).concat(arr.slice(i+1))).forEach(function(a) { res.push([x].concat(a)); }); }); return res; } console.log(perm([1,2,3,4]));


function nPr(xs, r) { if (!r) return []; return xs.reduce(function(memo, cur, i) { var others = xs.slice(0,i).concat(xs.slice(i+1)), perms = nPr(others, r-1), newElms = !perms.length ? [[cur]] : perms.map(function(perm) { return [cur].concat(perm) }); return memo.concat(newElms); }, []); }


function swap(array1, index1, index2) { var temp; temp = array1[index1]; array1[index1] = array1[index2]; array1[index2] = temp; } function permute(a, l, r) { var i; if (l == r) { console.log(a.join('''')); } else { for (i = l; i <= r; i++) { swap(a, l, i); permute(a, l + 1, r); swap(a, l, i); } } } permute(["A","B","C", "D"],0,3);

// ejecución de muestra // para más detalles, consulte este enlace

// http://www.geeksforgeeks.org/write-a-c-program-to-print-all-permutations-of-a-given-string/


var inputArray = [1, 2, 3]; var result = inputArray.reduce(function permute(res, item, key, arr) { return res.concat(arr.length > 1 && arr.slice(0, key).concat(arr.slice(key + 1)).reduce(permute, []).map(function(perm) { return [item].concat(perm); }) || item); }, []); alert(JSON.stringify(result));