Recursión 1

Permutación con repetición

by Juan Manuel Cruz

HTML

<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
  <input type="text" v-model="entrada" @keyup="permute">
  <p style="color: red;" v-show="entrada.length > 7">
    Cuidado! Las permutaciones crecen muy rápido y esto puede agotar los recursos de tu equipo
  </p>
  <p v-show="totalPermutations">Número total de permutaciones: {{ totalPermutations }}</p>
  <div class="grid" v-if="permutaciones.length">
    <p v-for="p in permutaciones">{{ p }}</p>
  </div>
  <p v-else>Ingrese algo en el campo de texto</p>
</div>

CSS

.grid {
      display: grid;
      grid-template-columns: repeat(5, 1fr);
    }

JavaScript

const factorial = (n, acc = 1) => n < 2 ? acc : factorial(n - 1, n * acc)
const reducer = (c, x) => {
  if (Object.keys(c).includes(x)) c[x] += 1
  else c[x] = 1
  return c
}
const string_to_array = x => typeof x === 'string' ? x.split('') : x
const number_to_string = x => typeof x === 'number' ? '' + x : x
const key_values = x => string_to_array( number_to_string( x ) ).reduce(reducer, {})

    var app = new Vue({
      el: '#app',
      data: {
      	entrada: '',
        permutaciones: []
      },
      computed: {
      	keyedValues () {
          return key_values(this.entrada)
        },
        fullLength () {
          return this.entrada.length
        },
        totalPermutations () {
          if (!this.entrada.length) return 0
          const values = Object.values(this.keyedValues)
          return factorial(this.fullLength) / values.reduce((c, x) => c * factorial(x), 1)
        },
        orderedKeys () {
          return Object.keys(this.keyedValues).sort()
        }
      },
      methods: {
    		permute () {
        	this.permutaciones = []
          let str = this.orderedKeys.join('')
          let count = this.orderedKeys.map(x => this.keyedValues[x])
          let result = this.orderedKeys.map(_ => 0)
          this.permutator(str, count, result, 0)
    		},
        permutator (str, count, result, level) {
          if (this.permutaciones.length === this.totalPermutations) return;
          if (level === this.fullLength) this.permutaciones.push(result.join(''))
          else str.split('').forEach((character, index) => {
            if (!count[index]) return;
            result[level] = character
            count[index] -= 1
            this.permutator(str, count, result.slice(0), level + 1)
            count[index] += 1
          })
        }
      }
    })