首页 文章

JavaScript中的排列?

提问于
浏览
106

我正在尝试编写一个执行以下操作的函数:

  • 将整数数组作为参数(例如[1,2,3,4])

  • 创建一个包含[1,2,3,4]所有可能排列的数组,每个排列的长度为4

下面的函数(我在网上找到)通过将一个字符串作为参数,然后返回该字符串的所有排列来完成此操作

我无法弄清楚如何修改它以使其与整数数组一起工作(我认为这与某些方法在字符串上的工作方式不同于在整数上的工作方式有关,但我不确定 . ..)

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
};

注意:我希望使函数返回整数数组, not 是一个字符串数组 .

我真的需要使用JavaScript的解决方案 . 我已经在python中找到了如何做到这一点

26 回答

  • 6
    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));
    
  • 21

    如果您注意到,代码实际上会在执行任何排列之前将字符拆分为数组,因此您只需删除连接和拆分操作

    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])));
    
  • 2

    不太晚,但想在这里添加一个稍微优雅的版本 . 可以是任何阵列......

    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);
    }
    

    添加ES6(2015)版本 . 也不会改变原始输入数组 . 适用于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;
    }
    

    所以...

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

    产量...

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

    和...

    permutator([1,2,3]);
    

    产量...

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

    以下非常有效的算法使用Heap's method生成N个元素的所有排列,运行时复杂度为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]));
    

    相同的算法实现为generator,空间复杂度为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])];
    

    性能比较

    随意将您的实现添加到以下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>
    

    Chrome 48的运行时结果:

  • 10

    我改进了SiGantenganswer .

    现在可以多次调用 permute ,因为每次都会清除 permArrusedChars .

    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])));
    
  • 5

    以下函数置换任何类型的数组,并在找到的每个排列上调用指定的回调函数:

    /*
      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);
      }
    

    如果你这样称呼它:

    // 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);
    

    我认为它将完全符合您的需要 - 使用数组[1,2,3]的排列填充一个名为 result 的数组 . 结果是:

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

    关于JSFiddle的更清晰的代码:http://jsfiddle.net/MgmMg/6/

  • 54

    此问题的大多数答案都使用昂贵的操作,如连续插入和删除数组中的项目,或重复复制数组 .

    相反,这是典型的回溯解决方案:

    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]  ]
    

    由于结果数组很大,因此逐个迭代结果而不是同时分配所有数据可能是个好主意 . 在ES6中,这可以通过生成器来完成:

    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}
    
  • 85

    无需外部阵列或附加功能即可接听

    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;
    }
    
  • 37

    一些版本受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])));
    
  • 2

    这是一项有趣的任务,这是我的贡献 . 它非常简单快速 . 如果有兴趣请耐心等待并继续阅读 .

    如果你想快速完成这项工作,你一定要进入动态编程 . 这意味着你应该忘记递归方法 . 这是肯定的...

    OK le_m's code使用Heap 's method seems to be the fastest so far. Well i haven' t得到了我的算法的名称,我已经实现了或者没有实现,但它非常简单快速 . 与所有动态编程方法一样,我们将从最简单的问题开始,并寻找最终结果 .

    假设我们有一个 a = [1,2,3] 数组,我们将开始

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

    然后按照这三个步骤;

    • 对于 r (result)数组的每一项,我们将添加输入数组的下一项 .

    • 我们将多次旋转每个项目的长度,并将每个实例存储在中间结果数组 t 中 . (除了第一个不浪费0转的时间)

    • 一旦我们完成 r 的所有项目,临时数组 t 应该保持下一级别的结果,所以我们生成 r = t; t = []; 并继续运行直到输入数组 a 的长度 .

    以下是我们的步骤;

    r array   | push next item to |  get length many rotations
              |  each sub array   |       of each subarray
    -----------------------------------------------------------
    [[1]]     |     [[1,2]]       |     [[1,2],[2,1]]
    ----------|-------------------|----------------------------
    [[1,2],   |     [[1,2,3],     |     [[1,2,3],[2,3,1],[3,1,2],
     [2,1]]   |      [2,1,3]]     |      [2,1,3],[1,3,2],[3,2,1]]
    ----------|-------------------|----------------------------
    previous t|                   |
    -----------------------------------------------------------
    

    所以这是代码

    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");
    

    在多次测试中,我已经看到它在25~35ms内解决了[0,1,2,3,4]的120次排列2000次 .

  • 0

    这是另一个“更递归”的解决方案 .

    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);
    

    输出:

    [ 'ABC', 'BAC', 'BCA', 'ACB', 'CAB', 'CBA' ]
    
  • -2
    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;
          }, []);
        }
    

    测试它:

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

    与@crl的Haskell风格解决方案类似,但使用 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
        }))
      },[])    
    }
    
  • 0
    #!/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]));
    
  • 4

    这是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)));
        }, []);
    }
    
    • 首先,我们处理基本情况,如果只有on项,则只返回数组它

    • 在所有其他情况下

    • 我们创建一个空数组

    • 循环输入数组

    • 并添加当前值的数组以及剩余数组的所有排列 [].concat(cv,a)

  • -3

    这是一个最小的ES6版本 . 可以从Lodash中拉出扁平且无功能的扁平状态 .

    const flatten = xs =>
        xs.reduce((cum, next) => [...cum, ...next], []);
    
    const without = (xs, x) =>
        xs.filter(y => y !== x);
    
    const permutations = xs =>
        flatten(xs.map(x =>
            xs.length < 2
                ? [xs]
                : permutations(without(xs, x)).map(perm => [x, ...perm])
        ));
    

    结果:

    permutations([1,2,3])
    // [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
    
  • 0

    大多数其他答案都没有使用新的javascript生成器函数,这是解决此类问题的完美解决方案 . 你可能在内存中只需要一次排列 . 此外,我更喜欢生成一系列索引的排列,因为这允许我索引每个排列并直接跳转到任何特定的排列,以及用于排列任何其他集合 .

    // 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)}`);
    
  • 0
    perm = x => x[0] ?  x.reduce((a, n) => (perm(x.filter(m => m!=n)).forEach(y => a.push([n,...y])), a), []): [[]]
    
  • 3

    我写了一个post来演示如何在JavaScript中置换数组 . 这是执行此操作的代码 .

    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("
    "); } 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; }

    打电话吧

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

    将工作 . 有关其工作原理的详细信息,请参阅该帖子中的说明 .

  • 2
    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);
        }, []);
    }
    
  • 0
    "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>
    

    输出按字典顺序排列的排列 . 仅适用于数字 . 在其他情况下,您必须在第34行更改交换方法 .

  • 0
    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)
          }
        })
      }
    

    结果:

    [ 
      [ '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' ] 
    ]
    
  • 2

    我对该网站的第一次贡献 . 有关代码背后算法的一些说明图,请参阅here . 此外,根据我所做的测试,此代码比此日期之前提到的所有其他方法运行得更快,当然,如果值很少,则它是最小的,但是当添加太多时,时间会呈指数增长 .

    function permutations(arr) {
        var finalArr = [];
        function iterator(arrayTaken, tree) {
            var temp;
            for (var i = 0; i < tree; i++) {
                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;
    };
    
  • 1
    const removeItem = (arr, i) => {
      return arr.slice(0, i).concat(arr.slice(i+1));
    }
    
    const makePermutations = (strArr) => {
      const doPermutation = (strArr, pairArr) => {
        return strArr.reduce((result, permutItem, i) => {
          const currentPair = removeItem(pairArr, i);
          const tempResult = currentPair.map((item) => permutItem+item);
          return tempResult.length === 1 ? result.concat(tempResult) :
                 result.concat(doPermutation(tempResult, currentPair));
        }, []);
      }
      return strArr.length === 1 ? strArr :
             doPermutation(strArr, strArr);
    }
    
    
    makePermutations(["a", "b", "c", "d"]);
    //result: ["abcd", "abdc", "acbd", "acdb", "adbc", "adcb", "bacd", "badc", "bcad", "bcda", "bdac", "bdca", "cabd", "cadb", "cbad", "cbda", "cdab", "cdba", "dabc", "dacb", "dbac", "dbca", "dcab", "dcba"]
    
  • 2

    这是一个非常简短的解决方案,仅适用于1或2个长字符串 . 它是一个oneliner,它使用ES6并且不依赖于jQuery,速度极快 . 请享用:

    var p = l => l.length<2 ? [l] : l.length==2 ? [l[0]+l[1],l[1]+l[0]] : Function('throw Error("unimplemented")')();
    
  • 1
    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);
    

    //示例执行//有关更多详细信息,请参阅此链接

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

相关问题