Saya mencoba menulis fungsi yang melakukan hal berikut:
- mengambil array bilangan bulat sebagai argumen (misalnya [1,2,3,4])
- membuat sebuah larik dari semua kemungkinan permutasi [1,2,3,4], dengan setiap permutasi memiliki panjang 4
fungsi di bawah ini (saya menemukannya online) melakukan ini dengan mengambil string sebagai argumen, dan mengembalikan semua permutasi string itu
Saya tidak tahu bagaimana memodifikasinya untuk membuatnya bekerja dengan array bilangan bulat, (saya pikir ini ada hubungannya dengan bagaimana beberapa metode bekerja secara berbeda pada string daripada yang mereka lakukan pada bilangan bulat, tapi saya tidak yakin. ..)
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
};
Catatan: Saya ingin membuat fungsi mengembalikan array bilangan bulat , bukan array string .
Saya sangat membutuhkan solusi untuk berada di JavaScript. Saya sudah menemukan cara melakukan ini dengan python
sumber
Sedikit terlambat, tetapi ingin menambahkan versi yang sedikit lebih elegan di sini. Bisa berupa larik apa saja ...
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); }
Menambahkan versi ES6 (2015). Juga tidak mengubah larik input asli. Berfungsi di konsol di 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; }
Begitu...
permutator(['c','a','t']);
Hasil ...
[ [ 'c', 'a', 't' ], [ 'c', 't', 'a' ], [ 'a', 'c', 't' ], [ 'a', 't', 'c' ], [ 't', 'c', 'a' ], [ 't', 'a', 'c' ] ]
Dan...
permutator([1,2,3]);
Hasil ...
[ [ 1, 2, 3 ], [ 1, 3, 2 ], [ 2, 1, 3 ], [ 2, 3, 1 ], [ 3, 1, 2 ], [ 3, 2, 1 ] ]
sumber
var results = new Array(factorial(inputArr.length)), length=0
, lalu gantiresults.push(…)
denganresults[length++]=…
var cur, memo = memo || [];
?slice()
dipermute(curr.slice(), m.concat(next))
benar-benar diperlukan?Algoritme yang sangat efisien berikut ini menggunakan metode Heap untuk menghasilkan semua permutasi elemen N dengan kompleksitas waktu proses dalam 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]));
Algoritma yang sama diimplementasikan sebagai generator dengan kompleksitas ruang di O (N):
Tampilkan cuplikan kode
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])];
Perbandingan kinerja
Jangan ragu untuk menambahkan implementasi Anda ke rangkaian pengujian benchmark.js berikut :
Tampilkan cuplikan kode
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; })(); function permute_Technicalbloke(inputArray) { if (inputArray.length === 1) return inputArray; return inputArray.reduce( function(accumulator,_,index){ permute_Technicalbloke([...inputArray.slice(0,index),...inputArray.slice(index+1)]) .map(value=>accumulator.push([inputArray[index],value])); return accumulator; },[]); } 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(); }) .add('permute_Technicalbloke', function() { permute_Technicalbloke(input); }) .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>
Hasil run-time untuk Chrome 48:
sumber
yield permutation.slice()
jika Anda tidak memotong Anda hanya mendapatkan permutasi terakhir yang dihitung.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));
sumber
.filter(uniq)
pada hasilnya.[1,2,3].length == 3 && "foo" || "bar"
atau[1,2].length == 3 && "foo" || "bar"
oh my! ada!(or (and (= 3 2) (print "hello!")) (print "goodbye"))
Saya telah meningkatkan SiGanteng 's jawaban .
Sekarang dimungkinkan untuk menelepon
permute
lebih dari sekali, karenapermArr
danusedChars
dibersihkan setiap kali.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; })(); }
Tampilkan cuplikan kode
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])));
sumber
Sebagian besar jawaban atas pertanyaan ini menggunakan operasi mahal seperti penyisipan berkelanjutan dan penghapusan item dalam larik, atau menyalin larik secara berulang.
Sebaliknya, ini adalah solusi mundur yang khas:
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] ]
Karena larik hasil akan sangat besar, mungkin ide yang baik untuk mengulang hasil satu per satu daripada mengalokasikan semua data secara bersamaan. Di ES6, ini dapat dilakukan dengan generator:
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}
sumber
Fungsi berikut mengubah array jenis apa pun dan memanggil fungsi panggilan balik yang ditentukan pada setiap permutasi yang ditemukan:
/* 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); }
Jika Anda menyebutnya seperti ini:
// 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);
Saya pikir itu akan melakukan apa yang Anda butuhkan - mengisi sebuah array yang disebut
result
dengan permutasi dari array [1, 2, 3]. Hasilnya adalah:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,2,1],[3,1,2]]
Kode yang sedikit lebih jelas di JSFiddle: http://jsfiddle.net/MgmMg/6/
sumber
Beberapa versi yang terinspirasi dari Haskell:
function perms(xs) { if (!xs.length) return [[]]; return xs.flatMap(x => { // get permutations of xs without x, then prepend x to each return perms(xs.filter(v => v!==x)).map(vs => [x, ...vs]); }); } document.write(JSON.stringify(perms([1,2,3])));
sumber
Ini adalah tugas yang menarik dan inilah kontribusi saya. Ini sangat sederhana dan cepat. Jika tertarik, mohon bersabar dan baca terus.
Jika Anda ingin melakukan pekerjaan ini dengan cepat, Anda pasti harus masuk ke dalam pemrograman dinamis. Yang berarti Anda harus melupakan pendekatan rekursif. Itu sudah pasti...
OK le_m kode yang menggunakan metode Heap tampaknya menjadi yang tercepat sejauh ini. Saya belum punya nama untuk algoritme saya, saya tidak tahu apakah itu sudah diterapkan atau belum tetapi sangat sederhana dan cepat. Seperti semua pendekatan pemrograman dinamis, kita akan mulai dengan masalah yang paling sederhana dan melanjutkan ke hasil akhir.
Dengan asumsi bahwa kita memiliki array yang
a = [1,2,3]
akan kita mulair = [[1]]; // result t = []; // interim result
Kemudian ikuti tiga langkah berikut;
r
array (result) kita, kita akan menambahkan item berikutnya dari array input.t
. (baik kecuali yang pertama tidak membuang waktu dengan 0 rotasi)r
array sementarat
harus menahan tingkat hasil berikutnya sehingga kita membuatr = t; t = [];
dan melanjutkan sampai panjang array masukana
.Jadi berikut ini adalah langkah-langkah kami;
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| | -----------------------------------------------------------
Jadi inilah kodenya
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");
Dalam beberapa tes saya telah melihatnya menyelesaikan 120 permutasi [0,1,2,3,4] untuk 2000 kali dalam 25 ~ 35ms.
sumber
rotatePerm
(yang di atas) secara konsisten 1.2 lebih cepat. Dengan FF tidak ada konsistensi. Setelah beberapa tes terkadangheapPerm
2 kali lebih cepat beberapa kalirotatePerm
1,1 kali lebih cepat. Dengan browser kit web lain seperti Opera atau EpiphanyrotatePerm
secara konsisten ternyata 1,1 kali lebih cepat. Namun dengan EdgeheapPerm
secara konsisten 1,2 kali lebih cepat setiap saat.permutations
fungsi standar :)Versi tercepat, paling (resorces) efektif dan paling elegan saat ini (2020)
function getArrayMutations (arr, perms = [], len = arr.length) { if (len === 1) perms.push(arr.slice(0)) for (let i = 0; i < len; i++) { getArrayMutations(arr, perms, len - 1) len % 2 // parity dependent adjacent elements swap ? [arr[0], arr[len - 1]] = [arr[len - 1], arr[0]] : [arr[i], arr[len - 1]] = [arr[len - 1], arr[i]] } return perms } const arrayToMutate = [1, 2, 3, 4, 5, 6, 7, 8, 9] const startTime = performance.now() const arrayOfMutations = getArrayMutations(arrayToMutate) const stopTime = performance.now() const duration = (stopTime - startTime) / 1000 console.log(`${arrayOfMutations.length.toLocaleString('en-US')} permutations found in ${duration.toLocaleString('en-US')}s`)
sumber
len % 2 // parity dependent adjacent elements swap
artinya dan mengapa itu digunakan?Menjawab tanpa memerlukan larik eksterior atau fungsi tambahan
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; }
sumber
Ini solusi yang keren
const rotations = ([l, ...ls], right=[]) => l ? [[l, ...ls, ...right], ...rotations(ls, [...right, l])] : [] const permutations = ([x, ...xs]) => x ? permutations(xs).flatMap((p) => rotations([x, ...p])) : [[]] console.log(permutations("cat"))
sumber
Ini adalah solusi lain yang "lebih rekursif".
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);
Keluaran:
[ 'ABC', 'BAC', 'BCA', 'ACB', 'CAB', 'CBA' ]
sumber
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; }, []); }
Uji dengan:
console.log(JSON.stringify(perm([1, 2, 3,4])));
sumber
Sebagian besar jawaban lain tidak memanfaatkan fungsi generator javascript baru yang merupakan solusi sempurna untuk jenis masalah ini. Anda mungkin hanya membutuhkan satu permutasi dalam memori. Selain itu, saya lebih suka menghasilkan permutasi dari berbagai indeks karena ini memungkinkan saya untuk mengindeks setiap permutasi dan langsung beralih ke permutasi tertentu serta digunakan untuk mengubah koleksi lainnya.
// 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)}`);
sumber
#!/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]));
sumber
Ini yang saya buat ...
const permute = (ar) => ar.length === 1 ? ar : ar.reduce( (ac,_,i) => {permute([...ar.slice(0,i),...ar.slice(i+1)]).map(v=>ac.push([].concat(ar[i],v))); return ac;},[]);
Dan ini dia lagi tetapi ditulis dengan kurang singkat! ...
function permute(inputArray) { if (inputArray.length === 1) return inputArray; return inputArray.reduce( function(accumulator,_,index){ permute([...inputArray.slice(0,index),...inputArray.slice(index+1)]) .map(value=>accumulator.push([].concat(inputArray[index],value))); return accumulator; },[]); }
Cara kerjanya: Jika array lebih panjang dari satu elemen, ia melangkah melalui setiap elemen dan menggabungkannya dengan panggilan rekursif ke dirinya sendiri dengan elemen yang tersisa sebagai argumennya. Itu tidak mengubah array asli.
sumber
Jawaban fungsional menggunakan flatMap:
const getPermutationsFor = (arr, permutation = []) => arr.length === 0 ? [permutation] : arr.flatMap((item, i, arr) => getPermutationsFor( arr.filter((_,j) => j !== i), [...permutation, item] ) );
sumber
Kontribusi pertama saya ke situs. Juga, menurut tes yang telah saya lakukan, kode ini berjalan lebih cepat daripada semua metode lain yang disebutkan di sini sebelum tanggal ini, tentu saja minimal jika nilainya sedikit, tetapi waktu meningkat secara eksponensial saat menambahkan terlalu banyak.
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; };
sumber
"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>
Menghasilkan permutasi yang diurutkan secara leksikografis. Bekerja hanya dengan angka. Dalam kasus lain, Anda harus mengubah metode swap di baris 34.
sumber
Semangat mirip dengan solusi gaya Haskell oleh @crl, tetapi bekerja dengan
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 })) },[]) }
sumber
Ini adalah kasus penggunaan yang sangat bagus untuk 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))); }, []); }
[].concat(cv,a)
sumber
Ini adalah versi ES6 minimal. Fungsi datar dan tanpa fungsi dapat ditarik dari 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]) ));
Hasil:
permutations([1,2,3]) // [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
sumber
perm = x => x[0] ? x.reduce((a, n) => (perm(x.filter(m => m!=n)).forEach(y => a.push([n,...y])), a), []): [[]]
sumber
const permutations = array => { let permut = []; helperFunction(0, array, permut); return permut; }; const helperFunction = (i, array, permut) => { if (i === array.length - 1) { permut.push(array.slice()); } else { for (let j = i; j < array.length; j++) { swapElements(i, j, array); helperFunction(i + 1, array, permut); swapElements(i, j, array); } } }; function swapElements(a, b, array) { let temp = array[a]; array[a] = array[b]; array[b] = temp; } console.log(permutations([1, 2, 3]));
sumber
Cukup telat. Masih berjaga-jaga jika ini membantu siapa pun.
function permute(arr) { if (arr.length == 1) return arr let res = arr.map((d, i) => permute([...arr.slice(0, i),...arr.slice(i + 1)]) .map(v => [d,v].join(''))).flat() return res } console.log(permute([1,2,3,4]))
sumber
Saya memiliki celah dalam membuat versi ini yang mencoba untuk menjadi singkat namun dapat dibaca, dan pemrograman murni fungsional.
function stringPermutations ([...input]) { if (input.length === 1) return input; return input .map((thisChar, index) => { const remainingChars = [...input.slice(0, index), ...input.slice(index + 1)]; return stringPermutations(remainingChars) .map(remainder => thisChar + remainder); }) .reduce((acc, cur) => [...acc, ...cur]); }
Perhatikan bahwa pemformatan argumen mengubah string input menjadi array. Tidak yakin apakah itu terlalu ajaib .. Tidak yakin saya pernah melihatnya di alam liar. Untuk keterbacaan yang nyata, saya mungkin akan melakukannya
input = [...input]
untuk baris pertama fungsi.sumber
Ini adalah implementasi dari algoritma Heap (mirip dengan @ le_m), kecuali itu rekursif.
function permute_kingzee(arr,n=arr.length,out=[]) { if(n == 1) { return out.push(arr.slice()); } else { for(let i=0; i<n; i++) { permute_kingzee(arr,n-1, out); let j = ( n % 2 == 0 ) ? i : 0; let t = arr[n-1]; arr[n-1] = arr[j]; arr[j] = t; } return out; } }
Sepertinya ini juga lebih cepat: https://jsfiddle.net/3brqzaLe/
sumber
Saya menulis posting untuk mendemonstrasikan bagaimana mengubah array dalam JavaScript. Berikut adalah kode yang melakukan ini.
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; }
Telepon saja
akan bekerja. Untuk detail tentang cara kerjanya, silakan lihat penjelasan di posting itu.
sumber
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); }, []); }
sumber