जावास्क्रिप्ट में क्रमपरिवर्तन


138

मैं एक फ़ंक्शन लिखने की कोशिश कर रहा हूं जो निम्नलिखित कार्य करता है:

  • एक तर्क के रूप में पूर्णांकों की एक सरणी लेता है (जैसे [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
};

नोट: मैं पूर्णांक के फ़ंक्शन रिटर्न एरेज़ बनाने के लिए देख रहा हूं , कि स्ट्रिंग्स की एक सरणी ।

मुझे वास्तव में जावास्क्रिप्ट में होने की आवश्यकता है। मैंने पहले ही पता लगा लिया है कि यह अजगर में कैसे करना है

जवाबों:


106

यदि आप ध्यान दें, तो कोड वास्तव में किसी भी क्रमपरिवर्तन करने से पहले एक सरणी में वर्णों को विभाजित करता है, इसलिए आप बस जॉइन और स्प्लिट ऑपरेशन को हटा दें

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


@SiGanteng। आपके कार्य का उपयोग करने के लिए कुछ अजीब हो रहा है। मैं इसे एक .js में रखता हूं जहां मेरे पास मेरी "सूची हेरफेर फ़ंक्शन" है। यदि मैं इसका उपयोग परमिट ([1,2,3]), और बाद में परमिट ([4,5,6]) के साथ करता हूं, तो बाद के आउटपुट में अभी भी परिणाम है, पहले वाले से आउटपुट। किसी भी विचार कैसे तय करने के लिए? बहुत धन्यवाद !
500


15
अपने फ़ंक्शन में ग्लोबल्स तक पहुंचना, खराब रूप!
श्मिट

123

थोड़ा देर से, लेकिन यहां थोड़ा और सुरुचिपूर्ण संस्करण जोड़ना पसंद करते हैं। कोई भी सरणी हो सकती है ...

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

ईएस 6 (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 ] ]

1
यदि आप एक भाज्य समारोह काम है (के रूप में काफी संभावना पर विचार आप क्रमपरिवर्तन साथ काम कर रहे है), तो आप इसे करने के लिए बाहरी गुंजाइश प्रारंभ बदलकर में तेजी लाने सकता है var results = new Array(factorial(inputArr.length)), length=0, तो बदलने के results.push(…)साथresults[length++]=…
Cyoce

1
रेखा क्या करती var cur, memo = memo || [];है?
राइसविंड

2
@ user2965967 यह वक्र और ज्ञापन की घोषणा करता है, और यह ज्ञापन को ज्ञापन के मूल्य के रूप में आरंभ करता है, जब तक कि यह गलत नहीं है (अपरिभाषित सहित), जिस स्थिति में यह एक खाली सरणी होगी। दूसरे शब्दों में, यह डिफ़ॉल्ट मान के साथ फ़ंक्शन पैरामीटर प्रदान करने के लिए आदर्श तरीके से कम है।
श्री लवलम्प

यह मूल सरणी को संशोधित करता है।
श्मिट

2
है slice()में permute(curr.slice(), m.concat(next))वास्तव में जरूरी?
योव

82

निम्नलिखित बहुत कुशल एल्गोरिथ्म हे (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]));

एक ही एल्गोरिथ्म O (N) में अंतरिक्ष जटिलता के साथ एक जनरेटर के रूप में लागू किया गया :

प्रदर्शन की तुलना

निम्नलिखित बेंचमार्क में अपने कार्यान्वयन को जोड़ने के लिए स्वतंत्र महसूस करें। टेस्ट सूट:

Chrome 48 के लिए रन-टाइम परिणाम:


1
निश्चित n = 2 के लिए परिणाम देने के लिए इस कोड को कैसे बदला जा सकता है? उदाहरण के लिए, मान लें कि हमारे पास तीन अक्षरों का एक सेट है: ए, बी और सी। हम पूछ सकते हैं कि हम उस सेट से कितने अक्षरों को व्यवस्थित कर सकते हैं। प्रत्येक संभावित व्यवस्था एक क्रमपरिवर्तन का उदाहरण होगी। संभावित परमिटों की पूरी सूची होगी: एबी, एसी, बीए, बीसी, सीए और सीबी।
a4xrbj1

1
@ a4xrbj1 इस प्रश्न में कोड नमूना देखें: stackoverflow.com/questions/37892738/… - या आप विशेष रूप से इसे (हीप) विधि को संशोधित करने के बारे में पूछ रहे हैं?
le_m

@le_m हाँ, विशेष रूप से इस (हीप) विधि का उपयोग करते हुए यह बहुत तेज़ है
a4xrbj1

@ a4xrbj1 मैं निश्चित लंबाई n के सभी संयोजनों की गणना करेगा (जैसे AB, AC, BC = n = 2 के लिए) ऊपर दी गई लिंक के लिए एक समान रणनीति का उपयोग करके (यह भी देखें stackoverflow.com/questions/127704/… ) और फिर प्रत्येक संयोजन के लिए। हीप की विधि का उपयोग करके अपने सभी क्रमपरिवर्तन की गणना करें। विशेष मामलों जैसे n = 2 को निश्चित रूप से अनुकूलित किया जा सकता है।
le_m

1
जनरेटर संस्करण ठीक से काम नहीं करता है, आपको यह करना चाहिए कि yield permutation.slice()यदि आप टुकड़ा नहीं करते हैं तो आपको केवल अंतिम क्रमचय की गणना मिलती है।
बेलदार

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

10
वाह, इसकी मरोड़ और डॉक्स की कमी के बावजूद, मुझे लगता है कि यह सबसे सुंदर जवाब है। इस एल्गोरिथ्म की मेरी व्याख्या है: सरणी (कम) में प्रत्येक आइटम के लिए, अन्य सभी आइटम का चयन करें, उन्हें अनुमति दें (पुनरावर्ती), और इस आइटम को संक्षिप्त करें।
अरोन

इस समाधान को यहाँ आज़माया गया: codewars.com/kata/reviews/5254ca2719453dcc0b000280/groups/… मैंने मूल गोल्फ कोड को एक पठनीय में बदल दिया है, लेकिन यह अनिवार्य रूप से समान है। इसके साथ समस्या यह है कि यह डुप्लिकेट का उत्पादन करता है, और मुझे .filter(uniq)परिणाम पर एक अतिरिक्त करना था ।
एंड्रे मिखायलोव - lolmaus

1
वहाँ एक लिस्प अवधारणा [1,2,3].length == 3 && "foo" || "bar"या [1,2].length == 3 && "foo" || "bar"ओह मेरे समानांतर है ! वहाँ है! (or (and (= 3 2) (print "hello!")) (print "goodbye"))
दिमित्री

@ lolmaus-AndreyMikhaylov डुप्लिकेट को हटाने का तरीका कृपया उत्तर को अपडेट करें यदि आप कर सकते हैं
Pardeep Jain

@PardeepJain मैंने ऊपर अपने समाधान का लिंक दिया।
एंड्री मिखायलोव - lolmaus

21

मैंने SiGanteng के उत्तर में सुधार किया है ।

अब permuteएक से अधिक बार कॉल करना संभव है , क्योंकि permArrऔर usedCharsहर बार साफ़ हो जाते हैं।

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


10

निम्न फ़ंक्शन किसी भी प्रकार के एक सरणी की अनुमति देता है और प्रत्येक क्रमांकन पर निर्दिष्ट कॉलबैक फ़ंक्शन को कॉल करता है:

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

मुझे लगता है कि यह वही करेगा जो आपको चाहिए - सरणी resultके क्रमपरिवर्तन [1, 2, 3] नामक एक सरणी भरें । परिणाम है:

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

JSFiddle पर थोड़ा स्पष्ट कोड: http://jsfiddle.net/MgmMg/6/


10

इस प्रश्न के अधिकांश उत्तर किसी सरणी में वस्तुओं के निरंतर सम्मिलन और विलोपन या दोहराए जाने वाले सरणियों की प्रतिलिपि बनाने जैसे महंगे संचालन का उपयोग करते हैं।

इसके बजाय, यह विशिष्ट पश्च समाधान है:

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}

6

यह एक दिलचस्प काम है और यहां मेरा योगदान है। यह बहुत सरल और तेज है। अगर दिलचस्पी है तो कृपया मेरे साथ रहें और आगे पढ़ें।

यदि आप इस काम को तेजी से करना चाहते हैं, तो आपको निश्चित रूप से खुद को गतिशील प्रोग्रामिंग में लाना होगा। जिसका अर्थ है कि आपको पुनरावर्ती दृष्टिकोणों के बारे में भूलना चाहिए। वह पक्का है...

ठीक है le_m कोड जो हीप विधि का उपयोग करता है वह अब तक का सबसे तेज़ लगता है। वैसे मुझे अपने एल्गोरिथ्म के लिए कोई नाम नहीं मिला है, मुझे नहीं पता कि यह पहले से ही लागू है या नहीं लेकिन यह बहुत सरल और तेज है। सभी गतिशील प्रोग्रामिंग दृष्टिकोणों के साथ हम सबसे सरल समस्या के साथ शुरू करेंगे और अंतिम परिणाम के लिए जाएंगे।

यह मानते हुए कि हमारे पास एक सरणी है, a = [1,2,3]हम साथ शुरू करेंगे

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

फिर इन तीन चरणों का पालन करें;

  1. हमारे r(परिणाम) सरणी के प्रत्येक आइटम के लिए हम इनपुट सरणी के अगले आइटम को जोड़ देंगे।
  2. हम प्रत्येक आइटम को कई बार लंबाई में घुमाएंगे और अंतरिम परिणाम सरणी में प्रत्येक उदाहरण को संग्रहीत करेंगे t। (अच्छी तरह से पहले के अलावा 0 रोटेशन के साथ समय बर्बाद करने के लिए नहीं)
  3. एक बार जब हम 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 ~ 35 सेमी में 2000 बार के लिए [0,1,2,3,4] के 120 क्रमोन्नति को हल करते हुए देखा है।


1
यह वास्तव में तेज, कभी-कभी तेज चलने लगता है, कभी-कभी अलग-अलग लंबाई / वार्म-अप पुनरावृत्तियों आदि के लिए एफएफ / उबंटू पर हीप विधि की तुलना में धीमा होता है।
le_m

1
@le_m ओके मैंने कुछ टेस्ट किए हैं @JSBen On Ubuntu & AMD CPU: क्रोम के साथ rotatePerm(ऊपर वाला) लगातार 1.2 तेज है। एफएफ के साथ कोई संगति नहीं है। कई परीक्षणों के बाद कभी-कभी heapPerm2 गुना तेजी से कुछ समय rotatePerm1.1 गुना तेज होता है। अन्य वेब-किट ब्राउज़र जैसे कि ओपेरा या एपिफेनी के साथ rotatePermलगातार 1.1 गुना तेजी से निकलता है। हालांकि एज heapPermहर एक समय में लगातार 1.2 गुना तेज है।
रेडू

1
अच्छा! ऐसा लगता है कि - कम से कम एफएफ / उबंटू पर - ढेर विधि का प्रदर्शन मुख्य रूप से सरणी प्रतिलिपि के प्रदर्शन पर निर्भर करता है। मैंने आपके बेंचमार्क को स्लाइडिंग बनाम पुशिंग की तुलना करने के लिए संशोधित किया: jsben.ch/#/x7mYh - FF पर और छोटे इनपुट सरणियों के लिए, धक्का ज्यादा तेज लगता है
le_m

2
बहुत अच्छा होगा यदि ढेर विधि को प्रदर्शन-वार पीटा जा सकता है। वैसे, आपकी विधि उसी उत्पादन को उत्पन्न करती है, जो लैंगडन के अल्गोरिद्म (पेज 16) के समान ही है, जिसे मैंने 1977 के पेपर में इस्तेमाल किया था, जो हीप की विधि के लिए एक संदर्भ के रूप में इस्तेमाल किया गया था: होमपेज.math.uiowa.edu/~goodman/22m150.dirin7/…
le_m

2
@le_m मैंने अभी जाँच की है और यह एक ही बात लगती है। मुझे लगता है जैसे उसने लागू किया रोटेशन। बस 40 साल की देरी से। जैसा कि मैंने अपने उत्तर में उल्लेख किया है कि यह वास्तव में एक बहुत ही सरल विधि है। तेजी से रोटेशन उपलब्ध होने पर ही चुनाव का उल्लेख किया गया है। वर्तमान में मैं हास्केल में हूं और इसमें अनिश्चित काल के लिए एक सूची बनाने (सरणी कहने) को चक्र बनाने की विधि है (आलसी मूल्यांकन एक अनंत पुनरावृत्ति को कोई समस्या नहीं बनाता है) और यह काम आ सकता है। फिर भी, हास्केल का पहले से ही एक मानक permutationsकार्य है :)
रेडू

6

हास्केल से प्रेरित कुछ संस्करण:

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

function perms(xs) {
  if (!xs.length) return [[]];
  return xs.flatMap((xi, i) => {
    // get permutations of xs without its i-th item, then prepend xi to each
    return perms([...xs.slice(0,i), ...xs.slice(i+1)]).map(xsi => [xi, ...xsi]);
  });
}
document.write(JSON.stringify(perms([1,2,3])));


5

बाहरी सरणी या अतिरिक्त फ़ंक्शन की आवश्यकता के बिना उत्तर दें

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

क्या आप इसमें से एक कॉम्बिनेशन बना सकते हैं? stackoverflow.com/questions/53555563/…
Techdive

5

सबसे तेज, सबसे (resorces) प्रभावी और सबसे सुंदर संस्करण आजकल (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`)


नमस्ते, क्या आप len % 2 // parity dependent adjacent elements swapइसका मतलब समझाते हैं और इसका उपयोग क्यों किया जाता है?
प्रमेश बजराचार्य

मेरा कोड सरणी क्रमपरिवर्तन उत्पन्न करने के लिए "हीप के एल्गोरिथ्म" का उपयोग करता है। इसलिए, यदि आप यह जानना चाहते हैं कि मेरा कोड हुड के तहत कैसे काम करता है, तो हीप के एल्गोरिथ्म के इस स्पष्टीकरण को पढ़ें: en.m.wikipedia.org/wiki/Heap%27s_algorithm
व्लादिस्लाव लाडकी

क्या आपने परिणाम प्रिंट करने की कोशिश की? अगर 10 से अधिक एरे तत्वों को अधिकतम कैसे नियंत्रित किया जाए?
मार्विक्स

4

यहाँ एक अच्छा समाधान है

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


2

यहाँ एक और "अधिक पुनरावर्ती" समाधान है।

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

क्या आप इसके लिए एक संयोजन बना सकते हैं? stackoverflow.com/questions/53555563/…
Techdive

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

2

अधिकांश अन्य उत्तर नए जावास्क्रिप्ट जनरेटर कार्यों का उपयोग नहीं करते हैं जो इस प्रकार की समस्या का एक सही समाधान है। आपको शायद स्मृति में समय पर केवल एक क्रमचय की आवश्यकता होती है। इसके अलावा, मैं सूचकांकों की एक श्रेणी का क्रमचय उत्पन्न करना पसंद करता हूं क्योंकि यह मुझे प्रत्येक क्रमांकन को अनुक्रमित करने और किसी भी विशेष क्रमपरिवर्तन के लिए सीधे कूदने की अनुमति देता है और साथ ही किसी अन्य संग्रह को क्रमबद्ध करने के लिए उपयोग किया जाता है।

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


2
#!/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]));

2

यहाँ एक मैंने बनाया है ...

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;},[]);

और यहाँ यह फिर से है, लेकिन कम tersely लिखा है! "

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;
  },[]);
}

यह कैसे काम करता है: यदि सरणी प्रत्येक तत्व के माध्यम से एक तत्व से अधिक लंबी है और इसे तर्क के रूप में शेष तत्वों के साथ खुद को पुनरावर्ती कॉल के साथ समेटता है। यह मूल सरणी को म्यूट नहीं करता है।


2

फ्लैटपाइप का उपयोग करके कार्यात्मक उत्तर:

const getPermutationsFor = (arr, permutation = []) =>
  arr.length === 0
    ? [permutation]
    : arr.flatMap((item, i, arr) =>
        getPermutationsFor(
          arr.filter((_,j) => j !== i),
          [...permutation, item]
        )
      );

1

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

आउटपुट lexicographically क्रमपरिवर्तन का आदेश दिया। केवल संख्या के साथ काम करता है। अन्य स्थिति में, आपको लाइन 34 पर स्वैप विधि को बदलना होगा।


1

@Crl द्वारा हास्केल-शैली समाधान की भावना के समान, लेकिन इसके साथ काम करना 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
    }))
  },[])    
}

1

यह मानचित्र / कम करने के लिए एक बहुत अच्छा उपयोग-मामला है:

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)

1

यहां न्यूनतम ईएस 6 संस्करण है। फ्लेटेन और बिना कार्यों को लॉडश से खींचा जा सकता है।

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

1
perm = x => x[0] ?  x.reduce((a, n) => (perm(x.filter(m => m!=n)).forEach(y => a.push([n,...y])), a), []): [[]]

2
क्या आप कृपया स्पष्टीकरण जोड़ सकते हैं।
मेहदी बोनाया

3
हालांकि यह उत्तर प्रश्न को हल कर सकता है , लेकिन इसमें ऐसा कैसे या क्यों किया गया, इसकी कोई व्याख्या नहीं है।
समले

1

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


1

काफी देर से। अभी भी सिर्फ अगर यह किसी की मदद करता है।

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


1

मेरे पास इसका एक संस्करण बनाने में दरार थी जो संक्षिप्त रूप से पठनीय होने का प्रयास करता है, और विशुद्ध रूप से कार्यात्मक प्रोग्रामिंग।

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

ध्यान दें कि तर्क स्वरूपण एक इनपुट स्ट्रिंग को एक सरणी में बदल देता है। यकीन है कि अगर यह थोड़ा बहुत जादुई है .. यकीन नहीं कि मैंने इसे जंगली में देखा है। वास्तविक पठनीयता के लिए मैं शायद input = [...input]फ़ंक्शन की पहली पंक्ति के लिए काम करूंगा ।


1

यह रीप्सिव को छोड़कर, हीप के एल्गोरिथ्म (@ le_m के समान) का कार्यान्वयन है।

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

ऐसा लगता है कि यह बहुत तेज़ है: https://jsfiddle.net/3brqzaLe/


1

साइट में मेरा पहला योगदान। इसके अलावा, मेरे द्वारा किए गए परीक्षणों के अनुसार, यह कोड इस तारीख से पहले यहां बताए गए अन्य सभी तरीकों की तुलना में तेजी से चलता है, निश्चित रूप से यह कम से कम है यदि कुछ मान हैं, लेकिन बहुत अधिक जोड़ने पर समय तेजी से बढ़ता है।

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

मैंने एक प्रदर्शन तुलना stackoverflow.com/a/37580979/1647737 जोड़ा - अपडेट करने के लिए स्वतंत्र महसूस करें।
le_m

0

मैंने एक पोस्ट लिखी थी कि जावास्क्रिप्ट में किसी सरणी को कैसे प्रदर्शित किया जाए। यहाँ कोड है जो यह करता है।

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

बस कॉल करना

परमिट ([], [१,२,३,४])

काम करेगा। यह कैसे काम करता है, इसके विवरण के लिए, कृपया उस पोस्ट में स्पष्टीकरण देखें।


0
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);
    }, []);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.