¿Permutaciones en JavaScript?

Resuelto pepperdreamteam asked hace 12 años • 41 respuestas

Estoy intentando escribir una función que haga lo siguiente:

  • toma una matriz de números enteros como argumento (por ejemplo, [1,2,3,4])
  • crea una matriz de todas las permutaciones posibles de [1,2,3,4], y cada permutación tiene una longitud de 4

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

No pude descubrir cómo modificarlo para que funcione con una matriz de números enteros (creo que esto tiene algo que ver con cómo algunos de los métodos funcionan de manera diferente en cadenas que en números enteros, pero no estoy seguro). ..)

let permArr = [];
let usedChars = [];

function permute(input) {
    const chars = input.split("");
    for (let i = 0; i < chars.length; i++) {
        const 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 que la función devuelva matrices de números enteros , no una matriz de cadenas .

Realmente necesito que la solución esté en JavaScript. Ya descubrí cómo hacer esto en Python.

pepperdreamteam avatar Apr 01 '12 07:04 pepperdreamteam
Aceptado

Un poco tarde, pero me gustaría agregar aquí una versión un poco más elegante. 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);
}

Agregando una versión ES6 (2015). Tampoco 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;
}

Entonces...

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 ] ]
delimited avatar Jan 01 '2014 18:01 delimited

El siguiente algoritmo muy eficiente utiliza 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]));
Expandir fragmento

El mismo algoritmo implementado como generador con complejidad espacial en O(N):

Mostrar fragmento de código

###Comparación de rendimiento No dude en agregar su implementación al siguiente conjunto de pruebas de benchmark.js :

Mostrar fragmento de código

Resultados en tiempo de ejecución para Chrome 48:

  •   99.152ms Este algoritmo
  •  153.115ms MarkusT
  •  401.255ms js-combinatoria
  •  497.037ms Urielzen
  •  925.669msOriol _
  • 1026.571ms SiGanteng
  • 2529.841ms delimitados
  • 3992.622ms mono
  • 4514.665msOriol _
le_m avatar Jun 02 '2016 00:06 le_m

Si se da cuenta, el código en realidad 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])));
Expandir fragmento

Andreas Wong avatar Apr 01 '2012 00:04 Andreas Wong
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));
monkey avatar Feb 27 '2014 08:02 monkey