जावास्क्रिप्ट सरणी को यादृच्छिक (फेरबदल) कैसे करें?


1263

मेरे पास एक सरणी है:

var arr1 = ["a", "b", "c", "d"];

मैं इसे कैसे यादृच्छिक / फेरबदल कर सकता हूं?



6
बस इसे यहाँ फेंकने से आप कल्पना कर सकते हैं कि वास्तव में इस विज़ुअलाइज़र माइक बोस्टॉक के
aug

5
@Blazemonger jsPref मर चुका है। क्या आप यहां सिर्फ वही पोस्ट कर सकते हैं जो सबसे तेज है?
1

एक-लाइनर के बारे में क्या? लौटाया गया सरणी बदल दिया गया है। arr1.reduce ((a, v) => a.plplice (Math.floor (Math.random) (0 a.length), 0, v) && a, []]
brunettdan

कम समाधान में ओ (एन ^ 2) जटिलता है। एक लाख तत्वों के साथ इसे एक सरणी पर चलाने का प्रयास करें।
riv

जवाबों:


1539

डी-फैक्टो निष्पक्ष फेरबदल एल्गोरिथ्म फिशर-येट्स (उर्फ नूथ) शफल है।

Https://github.com/coolaj86/knuth-shuffle देखें

आप यहां एक महान दृश्य देख सकते हैं (और मूल पोस्ट इसी से जुड़ी हुई है )

function shuffle(array) {
  var currentIndex = array.length, temporaryValue, randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}

// Used like so
var arr = [2, 11, 37, 42];
shuffle(arr);
console.log(arr);

उपयोग किए गए एल्गोरिथ्म के बारे में कुछ और जानकारी ।


13
उपरोक्त उत्तर तत्व 0 को छोड़ देता है, स्थिति i--नहीं होनी चाहिए --i। इसके अलावा, जब तक लूप कभी भी प्रवेश नहीं किया जाएगा , तब से परीक्षण if (i==0)...बहुत ही i == 0शानदार है । कॉल का उपयोग तेजी से किया जा सकता है । भीMath.floor...| 0 टेम्पाई या tempj हटाया जा सकता है और मूल्य सीधे को सौंपा जा myArray [i] या जे के रूप में उपयुक्त।
रोब

23
@prometheus, सभी RNG तब तक छद्म-यादृच्छिक होते हैं जब तक कि महंगे हार्डवेयर से कनेक्ट न हों।
फिल एच।

38
@ उपरोक्त कार्यान्वयन कार्यात्मक रूप से सही है। फिशर-येट्स एल्गोरिथ्म में, लूप सरणी में पहले तत्व के लिए चलाने के लिए नहीं है। चेक आउट विकिपीडिया जहां अन्य कार्यान्वयन वह भी पहला तत्व को छोड़ रहे हैं। इस लेख को भी देखें जो यह बताता है कि पहले तत्व के लिए लूप न चलाना क्यों महत्वपूर्ण है।
Theon

34
@ अनिकोला "बिल्कुल यादृच्छिक नहीं" मेरे लिए एक मजबूत योग्यता है। मेरा तर्क है कि जब तक आप एक क्रिप्टोग्राफर नहीं होते हैं, तब तक यह पर्याप्त रूप से यादृच्छिक होता है, जिस स्थिति में आप शायद पहली बार में Math.Random () का उपयोग नहीं कर रहे हैं।
तून81

20
ऊ, योदा ( 0 !== currentIndex)।
ffxsam

744

यहां डर्स्टनफील्ड फेरबदल का एक जावास्क्रिप्ट कार्यान्वयन , फिशर-येट्स का एक अनुकूलित संस्करण है:

/* Randomize array in-place using Durstenfeld shuffle algorithm */
function shuffleArray(array) {
    for (var i = array.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

यह प्रत्येक मूल सरणी तत्व के लिए एक यादृच्छिक तत्व चुनता है, और इसे अगले ड्रॉ से अलग करता है, जैसे कार्ड के डेक से यादृच्छिक रूप से चुनना।

यह चतुर बहिष्करण वर्तमान तत्व के साथ उठाया तत्व को स्वैप करता है, फिर शेष यादृच्छिक से अगले यादृच्छिक तत्व को उठाता है, इष्टतम दक्षता के लिए पीछे की ओर, यादृच्छिक पिक को सरलीकृत करना सुनिश्चित करता है (यह हमेशा 0 पर शुरू हो सकता है), और इस तरह अंतिम तत्व को छोड़ देता है।

एल्गोरिदम रनटाइम है O(n)ध्यान दें कि फेरबदल जगह में किया जाता है, इसलिए यदि आप मूल सरणी को संशोधित नहीं करना चाहते हैं, तो पहले इसकी एक प्रति बनाएं .slice(0)


EDIT: ES6 / ECMAScript 2015 का अद्यतन

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

function shuffleArray(array) {
    for (let i = array.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }
}

22
ps क्रिस्टोफडी के उत्तर के रूप में एक ही एल्गोरिथ्म, लेकिन स्पष्टीकरण और क्लीनर कार्यान्वयन के साथ।
लॉरेंस होल्स्ट

12
एल्गोरिथम के लिए लोग गलत व्यक्ति को जिम्मेदार ठहरा रहे हैं। यह फिशर-येट्स फेरबदल नहीं है, लेकिन डर्स्टनफील्ड फेरबदल है । असली मूल फिशर-येट्स एल्गोरिथ्म n ^ 2 समय में चलता है, n समय नहीं
Pacerier

7
return arrayफ़ंक्शन तर्कों के रूप में उपयोग किए जाने के बाद जावास्क्रिप्ट को संदर्भों से पास होने की आवश्यकता नहीं है। मुझे लगता है कि यह स्टैक स्पेस को बचाने के लिए है, लेकिन यह एक छोटी सी विशेषता है। सरणी पर फेरबदल करना मूल सरणी को फेरबदल करेगा।
जोएल ट्रैगर

5
इस उत्तर में कार्यान्वयन सरणी के निचले छोर का पक्षधर है। कठिन रास्ता खोज लियाMath.random() should not be multiplied with the loop counter + 1, but with array.lengt () `। एक विशिष्ट श्रेणी में जावास्क्रिप्ट में यादृच्छिक पूर्ण संख्या उत्पन्न करना देखें ? बहुत व्यापक व्याख्या के लिए।
मार्जन वेनमा

13
@MarjanVenema सुनिश्चित नहीं हैं कि आप अभी भी इस जगह को देख रहा है, तो कर रहे हैं, लेकिन इस सवाल का जवाब है सही, और परिवर्तन आप सुझाव दे रहे हैं वास्तव में पूर्वाग्रह परिचय देता है। इस गलती का अच्छा लिखने के लिए blog.codinghorror.com/the-danger-of-naivete देखें ।
user94559

133

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

[1,2,3,4,5,6].sort(function() {
  return .5 - Math.random();
});

13
मुझे यह समाधान पसंद है
एलेक्स के

147
डाउनवोटिंग के रूप में यह वास्तव में यादृच्छिक नहीं है। मुझे नहीं पता कि इसमें इतने सारे बदलाव क्यों हैं। इस विधि का उपयोग न करें। यह सुंदर लग रहा है, लेकिन पूरी तरह से सही नहीं है। आपके व्यूअर इंडेक्स में हर बार कितनी संख्या [१०] (मैं अन्य परिणाम भी दे सकता हूं) पर १०,००० पुनरावृत्तियों के बाद परिणाम हैं: १ = २ ९ .१ ९%, २ = २ ९ .५३%, ३ = २०.०६%, ४ = ११.९ ०%। 5 = 5.99%, 6 = 3.32%
radtad

8
यह ठीक है अगर आपको अपेक्षाकृत छोटे सरणी को यादृच्छिक बनाने और क्रिप्टोग्राफ़िक चीजों से निपटने की आवश्यकता नहीं है। मैं पूरी तरह से सहमत हूं कि यदि आपको अधिक यादृच्छिकता की आवश्यकता है तो आपको अधिक जटिल समाधान का उपयोग करने की आवश्यकता है।
डेडक्रैक


12
समस्या यह है कि यह निर्धारक नहीं है, जो गलत परिणाम देगा (यदि 1> 2 और 2> 3, तो यह दिया जाना चाहिए कि 1> 3, लेकिन यह इस बात की गारंटी नहीं देगा। यह इस प्रकार को भ्रमित करेगा, और परिणाम टिप्पणी देगा। @ भारद्वाड द्वारा)।
मात्स्लिंध 14

73

एक (या) यह ऐरे से एक प्रोटॉयपे के रूप में उपयोग कर सकता है:

क्रिस्टोफ़ से:

Array.prototype.shuffle = function() {
  var i = this.length, j, temp;
  if ( i == 0 ) return this;
  while ( --i ) {
     j = Math.floor( Math.random() * ( i + 1 ) );
     temp = this[i];
     this[i] = this[j];
     this[j] = temp;
  }
  return this;
}

42
वास्तव में इसका कोई फायदा नहीं, IMOHO, किसी और के कार्यान्वयन पर संभवतः दबाव डालने के अलावा ..
user2864740

2
यदि ऐरे प्रोटोटाइप में उपयोग किया जाता है, तो इसे केवल फेरबदल के अलावा अन्य नाम दिया जाना चाहिए ।
वुल्फ

57
एक (या चाहिए) मूल
सिद्धांतों को

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

18
@TinyGiant वास्तव में: for...inसरणियों पर पुनरावृति करने के लिए छोरों का उपयोग न करें ।
कॉनर ओ'ब्रायन

69

आप इसे आसानी से मानचित्र और सॉर्ट के साथ कर सकते हैं:

let unshuffled = ['hello', 'a', 't', 'q', 1, 2, 3, {cats: true}]

let shuffled = unshuffled
  .map((a) => ({sort: Math.random(), value: a}))
  .sort((a, b) => a.sort - b.sort)
  .map((a) => a.value)
  1. हम प्रत्येक तत्व को एक ऑब्जेक्ट में सरणी में रखते हैं, और इसे एक यादृच्छिक सॉर्ट कुंजी देते हैं
  2. हम यादृच्छिक कुंजी का उपयोग कर सॉर्ट करते हैं
  3. हम मूल वस्तुओं को पाने के लिए तैयार नहीं होते हैं

आप बहुरंगी सरणियों को फेरबदल कर सकते हैं, और यह छांटना Math.random की तरह यादृच्छिक है, जो अधिकांश उद्देश्यों के लिए पर्याप्त है।

चूंकि तत्वों को लगातार कुंजियों के खिलाफ क्रमबद्ध किया जाता है जो प्रत्येक पुनरावृत्ति को पुनर्जीवित नहीं करते हैं, और प्रत्येक तुलना समान वितरण से खींचती है, Math.random के वितरण में किसी भी गैर-यादृच्छिकता को रद्द कर दिया जाता है।

गति

समय जटिलता ओ (एन लॉग एन) है, जो त्वरित सॉर्ट के समान है। अंतरिक्ष जटिलता O (N) है। यह एक फिशर येट्स फेरबदल के रूप में कुशल नहीं है लेकिन, मेरी राय में, कोड काफी छोटा और अधिक कार्यात्मक है। यदि आपके पास एक बड़ा सरणी है तो आपको निश्चित रूप से फिशर येट्स का उपयोग करना चाहिए। यदि आपके पास कुछ सौ वस्तुओं के साथ एक छोटा सा सरणी है, तो आप ऐसा कर सकते हैं।


1
@superluminary उफ़, आप सही कह रहे हैं। ध्यान दें कि इस उत्तर ने पहले से ही समान दृष्टिकोण का उपयोग किया है।
बरगी

@Bergi - आह हाँ, आप सही हैं, हालांकि मुझे लगता है कि मेरा कार्यान्वयन थोड़ा प्रीतिकर है।
superluminary

3
बहुत अच्छा। यह js में श्वार्टज़ियन परिवर्तन है।
मार्क ग्रिम्स

@torazaburo - यह फिशर येट्स के रूप में प्रदर्शन करने वाला नहीं है, लेकिन यह सुंदर है और कोड छोटा है। कोड हमेशा एक व्यापार बंद है। यदि मेरे पास एक बड़ा सरणी है, तो मैं नथ का उपयोग करूंगा। अगर मेरे पास एक सौ आइटम होते, तो मैं ऐसा करता।
Superluminary

1
@BenCarp - सहमत, यह सबसे तेज़ समाधान नहीं है और आप इसे बड़े पैमाने पर उपयोग नहीं करना चाहेंगे, लेकिन कच्ची गति की तुलना में कोड में अधिक विचार हैं।
superluminary

64

अंडरस्कोर .js लाइब्रेरी का उपयोग करें। _.shuffle()इस मामले के लिए विधि अच्छी है। यहाँ विधि के साथ एक उदाहरण दिया गया है:

var _ = require("underscore");

var arr = [1,2,3,4,5,6];
// Testing _.shuffle
var testShuffle = function () {
  var indexOne = 0;
    var stObj = {
      '0': 0,
      '1': 1,
      '2': 2,
      '3': 3,
      '4': 4,
      '5': 5
    };
    for (var i = 0; i < 1000; i++) {
      arr = _.shuffle(arr);
      indexOne = _.indexOf(arr, 1);
      stObj[indexOne] ++;
    }
    console.log(stObj);
};
testShuffle();

12
बहुत बढ़िया जवाब! धन्यवाद। मैं इसे अन्य उत्तरों के लिए पसंद करता हूं, क्योंकि यह लोगों को पुस्तकालयों का उपयोग करने के बजाय हर जगह संभावित छोटी-छोटी क्रियाओं को कॉपी और पेस्ट करने के लिए प्रोत्साहित करता है।
frabcus

60
@frabcus: केवल एक shuffleफ़ंक्शन प्राप्त करने के लिए पूरी लाइब्रेरी को शामिल करने का कोई मतलब नहीं है ।
ब्लंडर

11
मैं @ ब्लेंडर से असहमत हूं। एक संपूर्ण लाइब्रेरी को शामिल करने के कई कारण हैं, बस आपको एक फ़ंक्शन की आवश्यकता है। उनमें से एक वहाँ बग का कम जोखिम है जब आप इसे लिखते हैं। यदि यह एक प्रदर्शन समस्या है, तो आपको इसका उपयोग नहीं करना चाहिए। लेकिन सिर्फ इसलिए कि यह एक प्रदर्शन समस्या हो सकती है इसका मतलब यह नहीं है कि यह होगा।
डैनियल कपलान

7
@tieTYT: तो आपको बाकी लाइब्रेरी की आवश्यकता क्यों है? फिशर-येट्स फेरबदल को लागू करने के लिए तुच्छ है। आपको सरणी से बाहर एक यादृच्छिक तत्व लेने के लिए पुस्तकालय की आवश्यकता नहीं है (मुझे आशा है), इसलिए पुस्तकालय का उपयोग करने का कोई कारण नहीं है जब तक कि आप वास्तव में इससे एक से अधिक फ़ंक्शन का उपयोग करने के लिए नहीं जा रहे हों।
ब्लेंडर

18
@ ब्लेंडर: मैंने एक वजह बताई। 1) मैं आपको विश्वास दिलाता हूं, आप अपने द्वारा लिखे गए किसी भी कोड में बग का परिचय दे सकते हैं, चाहे वह कितना भी तुच्छ क्यों न हो। यह जोखिम क्यों है? 2) पूर्व-अनुकूलन न करें। 3) 99% उस समय जब आपको एक फेरबदल की आवश्यकता होती है, आपका ऐप एक फेरबदल अहंकार लिखने के बारे में नहीं है। यह एक ऐसी चीज के बारे में है जिसे फेरबदल की जरूरत है। दूसरों के काम का लाभ उठाएं। जब तक आपको नहीं करना है, तब तक कार्यान्वयन विवरण के बारे में न सोचें।
डेनियल कपलान

50

नया!

कम और शायद * तेज फिशर-येट्स फेरबदल एल्गोरिथ्म

  1. जबकि यह उपयोग करता है ---
  2. मंजिल के लिए बिटवाइज़ (10 दशमलव अंकों तक की संख्या (32 बिट))
  3. आवश्यक क्लोजर और अन्य सामान को हटा दिया

function fy(a,b,c,d){//array,placeholder,placeholder,placeholder
 c=a.length;while(c)b=Math.random()*(--c+1)|0,d=a[c],a[c]=a[b],a[b]=d
}

स्क्रिप्ट का आकार (fy के रूप में फ़ंक्शन नाम के साथ): 90bytes

डेमो http://jsfiddle.net/vvpoma8w/

* तेजी से क्रोम को छोड़कर सभी ब्राउज़रों पर।

अगर आप को कोई भी सवाल है, तो बस पूछो।

संपादित करें

हाँ यह तेज है

प्रदर्शन: http://jsperf.com/fyshuffle

शीर्ष मतदान कार्यों का उपयोग करना।

संपादित करें अतिरिक्त में एक गणना थी (आवश्यकता नहीं है - c + 1) और किसी का ध्यान नहीं गया

कम (4bytes) और तेज (इसे परीक्षण!)।

function fy(a,b,c,d){//array,placeholder,placeholder,placeholder
 c=a.length;while(c)b=Math.random()*c--|0,d=a[c],a[c]=a[b],a[b]=d
}

कहीं और कैशिंग var rnd=Math.randomऔर फिर उपयोग से rnd()बड़े सरणियों पर प्रदर्शन में थोड़ी वृद्धि होगी।

http://jsfiddle.net/vvpoma8w/2/

पठनीय संस्करण (मूल संस्करण का उपयोग करें। यह धीमा है, संस्करण बंद की तरह बेकार हैं और ";"; कोड स्वयं भी छोटा है ... हो सकता है कि यह कैसे पढ़ें 'जावास्क्रिप्ट को छोटा करें' , btw आप सक्षम नहीं हैं उपरोक्त कोड की तरह एक जावास्क्रिप्ट मिनिफ़र में निम्नलिखित कोड को संपीड़ित करें।)

function fisherYates( array ){
 var count = array.length,
     randomnumber,
     temp;
 while( count ){
  randomnumber = Math.random() * count-- | 0;
  temp = array[count];
  array[count] = array[randomnumber];
  array[randomnumber] = temp
 }
}

6
प्रदर्शन की जांच करें ... अधिकांश ब्राउज़रों पर तेजी से 2x ... लेकिन अधिक जेस्पर्फ़ परीक्षकों की आवश्यकता है ...
cocco

10
js एक ऐसी भाषा है जो इसे लिखने के लिए कई शॉर्टकट और विभिन्न तरीकों को स्वीकार करती है .. जबकि यहाँ कई धीमे पठनीय कार्य हैं जैसे कि मैं यह दिखाना चाहता हूँ कि इसे और अधिक शानदार तरीके से कैसे किया जा सकता है, कुछ बाइट्स को सहेज कर भी ... आशुलिपि वास्तव में यहाँ कम करके आंका गया है और वेब छोटी गाड़ी और धीमी कोड से भरा है।
cocco

नहीं एक स्लैम डुंक पूर्ण वृद्धि। अदला-बदली fyऔर shuffle prototype, मैं मिल fyपर ओएस एक्स 10.9.5 क्रोम 37 में नीचे (81% धीमी ~ ~ 100k की तुलना में 20k ऑप्स) और सफारी 7.1 पर लगातार यह 8% धीमी ~ पर निर्भर है। YMMV, लेकिन यह हमेशा तेज़ नहीं होता है। jsperf.com/fyshuffle/3
Spig

आँकड़ों को फिर से जाँचें ... मैंने पहले ही लिखा था कि क्रोम धीमा है क्योंकि वे मठ को अनुकूलित करते हैं, अन्य सभी बिटवाइज़ फ़्लोर पर और जबकि तेज़ है। जाँच IE, फ़ायरफ़ॉक्स, लेकिन यह भी मोबाइल उपकरणों। भी ओपेरा को देखने के लिए अच्छा हो ...
cocco

1
यह एक भयानक जवाब है। एसओ एक अस्पष्ट प्रतियोगिता नहीं है।
पिल्ला

39

संपादित करें: यह उत्तर गलत है

टिप्पणियाँ और https://stackoverflow.com/a/18650169/28234 देखें । यह संदर्भ के लिए यहां छोड़ा जा रहा है क्योंकि विचार दुर्लभ नहीं है।


छोटे सरणियों के लिए एक बहुत ही सरल तरीका यह है:

const someArray = [1, 2, 3, 4, 5];

someArray.sort(() => Math.random() - 0.5);

यह शायद बहुत कुशल नहीं है, लेकिन छोटे सरणियों के लिए यह ठीक काम करता है। यहां एक उदाहरण दिया गया है ताकि आप देख सकें कि यह कितना यादृच्छिक (या नहीं) है, और यह आपके usecase में फिट बैठता है या नहीं।

const resultsEl = document.querySelector('#results');
const buttonEl = document.querySelector('#trigger');

const generateArrayAndRandomize = () => {
  const someArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
  someArray.sort(() => Math.random() - 0.5);
  return someArray;
};

const renderResultsToDom = (results, el) => {
  el.innerHTML = results.join(' ');
};

buttonEl.addEventListener('click', () => renderResultsToDom(generateArrayAndRandomize(), resultsEl));
<h1>Randomize!</h1>
<button id="trigger">Generate</button>
<p id="results">0 1 2 3 4 5 6 7 8 9</p>


एक अच्छा है, लेकिन हर बार एक पूर्ण यादृच्छिक तत्व उत्पन्न करता है?
DDD

बिल्कुल सही नहीं अगर मैं तुम्हें सही ढंग से समझ गया। हर बार जब आप सॉर्ट सरणी को कॉल करते हैं, तो यह दृष्टिकोण सरणी को यादृच्छिक तरीके से अलग कर देगा (यद्यपि छद्म-यादृच्छिक) - यह स्पष्ट कारणों के लिए एक स्थिर सॉर्ट नहीं है।
क्रिस सेलबक

4
एक ही कारण के लिए के रूप में समझाया stackoverflow.com/a/18650169/28234 । यह सरणी की शुरुआत के पास शुरुआती तत्वों को छोड़ने की अधिक संभावना है।
एलेक्सा

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

1
अगर यह काम करता तो यह प्यारा होता, लेकिन ऐसा नहीं है। त्वरित खोज के काम के तरीके के कारण, एक असंगत तुलनित्र अपने मूल स्थान के करीब सरणी तत्वों को छोड़ने की संभावना रखेगा। आपके सरणी को तराशा नहीं जाएगा।
सुपरल्यूमिनरी

39

विश्वसनीय, कुशल, लघु

इस पृष्ठ पर कुछ समाधान विश्वसनीय नहीं हैं (वे केवल सरणी को आंशिक रूप से यादृच्छिक करते हैं)। अन्य समाधान काफी कम कुशल हैं। साथ testShuffleArrayFun(नीचे देखें) हम विश्वसनीयता और प्रदर्शन के लिए सरणी फेरबदल कार्यों का परीक्षण कर सकते हैं। निम्नलिखित समाधान हैं: विश्वसनीय, कुशल और संक्षिप्त (ES6 सिंटैक्स का उपयोग करके)

[ testShuffleArrayFunGoogle Chrome में अन्य समाधानों के विरुद्ध तुलनात्मक परीक्षण किए गए ]

जगह में फेरबदल

    function getShuffledArr (array){
        for (var i = array.length - 1; i > 0; i--) {
            var rand = Math.floor(Math.random() * (i + 1));
            [array[i], array[rand]] = [array[rand], array[i]]
        }
    }

ईएस 6 शुद्ध, Iterative

    const getShuffledArr = arr => {
        const newArr = arr.slice()
        for (let i = newArr.length - 1; i > 0; i--) {
            const rand = Math.floor(Math.random() * (i + 1));
            [newArr[i], newArr[rand]] = [newArr[rand], newArr[i]];
        }
        return newArr
    };

विश्वसनीयता और प्रदर्शन परीक्षण

जैसा कि आप इस पृष्ठ में देख सकते हैं, अतीत में यहाँ गलत समाधान पेश किए गए हैं। मैंने किसी भी शुद्ध (कोई साइड इफेक्ट) सरणी यादृच्छिक कार्यों का परीक्षण करने के लिए निम्नलिखित फ़ंक्शन का उपयोग किया और लिखा है।

    function testShuffleArrayFun(getShuffledArrayFun){
        const arr = [0,1,2,3,4,5,6,7,8,9]

        var countArr = arr.map(el=>{
            return arr.map(
                el=> 0
            )
        }) //   For each possible position in the shuffledArr and for 
           //   each possible value, we'll create a counter. 
        const t0 = performance.now()
        const n = 1000000
        for (var i=0 ; i<n ; i++){
            //   We'll call getShuffledArrayFun n times. 
            //   And for each iteration, we'll increment the counter. 
            var shuffledArr = getShuffledArrayFun(arr)
            shuffledArr.forEach(
                (value,key)=>{countArr[key][value]++}
            )
        }
        const t1 = performance.now()
        console.log(`Count Values in position`)
        console.table(countArr)

        const frequencyArr = countArr.map( positionArr => (
            positionArr.map(  
                count => count/n
            )
        )) 

        console.log("Frequency of value in position")
        console.table(frequencyArr)
        console.log(`total time: ${t1-t0}`)
    }

अन्य समाधान

सिर्फ मनोरंजन के लिए अन्य समाधान।

ईएस 6 शुद्ध, पुनरावर्ती

    const getShuffledArr = arr => {
        if (arr.length === 1) {return arr};
        const rand = Math.floor(Math.random() * arr.length);
        return [arr[rand], ...getShuffledArr(arr.filter((_, i) => i != rand))];
    };

ES6 शुद्ध array.map का उपयोग कर

    function getShuffledArr (arr){
        return [...arr].map( (_, i, arrCopy) => {
            var rand = i + ( Math.floor( Math.random() * (arrCopy.length - i) ) );
            [arrCopy[rand], arrCopy[i]] = [arrCopy[i], arrCopy[rand]]
            return arrCopy[i]
        })
    }

ES6 शुद्ध array.reduce का उपयोग कर

    function getShuffledArr (arr){
        return arr.reduce( 
            (newArr, _, i) => {
                var rand = i + ( Math.floor( Math.random() * (newArr.length - i) ) );
                [newArr[rand], newArr[i]] = [newArr[i], newArr[rand]]
                return newArr
            }, [...arr]
        )
    }

तो, ES6 (ES2015) कहां है? [array[i], array[rand]]=[array[rand], array[i]]? शायद आप इस बात को रेखांकित कर सकते हैं कि यह कैसे काम करता है। आप नीचे की ओर पुनरावृति क्यों चुनते हैं?
sheriffderek

@sheriffderek हां, मैं जिस ES6 फीचर का उपयोग कर रहा हूं, वह एक ही बार में दो वेरिएंट का असाइनमेंट है, जो हमें कोड की एक लाइन में दो वेरिएप स्वैप करने की अनुमति देता है।
बेन कार्प

श्रेय @sheriffderek को जिन्होंने आरोही एल्गोरिथम का सुझाव दिया था। आरोही एल्गोरिथ्म को प्रेरण में साबित किया जा सकता है।
बेन कार्प

23

@Laurens Holsts जवाब में जोड़ना। यह 50% संकुचित है।

function shuffleArray(d) {
  for (var c = d.length - 1; c > 0; c--) {
    var b = Math.floor(Math.random() * (c + 1));
    var a = d[c];
    d[c] = d[b];
    d[b] = a;
  }
  return d
};

3
हमें स्टैक ओवरफ्लो से कोड चिपकाने के बजाय लोगों को _.shuffle का उपयोग करने के लिए प्रोत्साहित करना चाहिए; और, हमें लोगों को अपने ढेर के अतिप्रवाह उत्तरों को संकुचित करने से हतोत्साहित करना चाहिए। यही जैस्मीन के लिए है।
डेविड जोन्स

45
@ डेविडजोन: मैं एक सरणी में फेरबदल करने के लिए पूरे 4kb पुस्तकालय को शामिल क्यों करूंगा?
ब्लेंडर

1
@KingKongFrog नाम कॉलिंग भी एक उचित समुदाय के संयोजन के लिए प्रवाहकीय नहीं है।
गेहूं

2
क्या यह var b = बाहरी लूप घोषित करने के बजाय लूप में करने के लिए कुशल है और इसे लूप में असाइन करना है b = ?
एलेक्स के

2
@ ब्रायन कोई फर्क नहीं पड़ेगा; स्रोत कोड पार्स होने पर उत्थापन होता है। शायद शामिल नहीं है।
user2864740

23

संपादित करें: यह उत्तर गलत है

Https://stackoverflow.com/a/18650169/28234 देखें । यह संदर्भ के लिए यहां छोड़ा जा रहा है क्योंकि विचार दुर्लभ नहीं है।

//one line solution
shuffle = (array) => array.sort(() => Math.random() - 0.5);


//Demo
let arr = [1, 2, 3];
shuffle(arr);
alert(arr);

https://javascript.info/task/shuffle

Math.random() - 0.5 एक यादृच्छिक संख्या है जो सकारात्मक या नकारात्मक हो सकती है, इसलिए छँटाई फ़ंक्शन यादृच्छिक तत्वों को पुन: व्यवस्थित करता है।


17

ES2015 के साथ आप इसका उपयोग कर सकते हैं:

Array.prototype.shuffle = function() {
  let m = this.length, i;
  while (m) {
    i = (Math.random() * m--) >>> 0;
    [this[m], this[i]] = [this[i], this[m]]
  }
  return this;
}

उपयोग:

[1, 2, 3, 4, 5, 6, 7].shuffle();

4
छंटनी करने के लिए, आपको n >>> 0इसके बजाय का उपयोग करना चाहिए ~~n। ऐरे इंडेक्स 2 be-1 से अधिक हो सकते हैं।
ओरियल

1
इस तरह के विनाशकारी इस तरह के एक स्वच्छ कार्यान्वयन के लिए बनाता है +1
ल्यूकजैकसन

14

मुझे इस प्रश्न के डुप्लिकेट पर "लेखक द्वारा हटाए गए" उत्तर में यह संस्करण लटका हुआ मिला। कुछ अन्य उत्तरों के विपरीत जिनमें पहले से ही कई उतार-चढ़ाव हैं, यह है:

  1. वास्तव में यादृच्छिक
  2. इन-प्लेस नहीं (इसलिए shuffledनाम के बजाय shuffle)
  3. पहले से ही कई वेरिएंट के साथ यहां मौजूद नहीं है

यहाँ एक jsfiddle यह उपयोग में दिखा रहा है

Array.prototype.shuffled = function() {
  return this.map(function(n){ return [Math.random(), n] })
             .sort().map(function(n){ return n[1] });
}

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

1
हाँ, लेकिन यह देखते हुए कि प्रसिद्ध गलत उत्तर अभी भी वोटों के एक समूह के साथ है, एक अक्षम लेकिन सही समाधान कम से कम उल्लेख किया जाना चाहिए।
डैनियल मार्टिन

[1,2,3,4,5,6].sort(function() { return .5 - Math.random(); }); - यह एक यादृच्छिक प्रकार नहीं देता है, और यदि आप इसका उपयोग करते हैं तो आप शर्मिंदा हो सकते हैं: robweir.com/blog/2010/02/microsoft-random-browser-ballot.html
डैनियल मार्टिन

3
.sort(function(a,b){ return a[0] - b[0]; })यदि आप क्रमबद्ध रूप से मानों की तुलना करना चाहते हैं तो आपको इसका उपयोग करने की आवश्यकता है । डिफ़ॉल्ट .sort()तुलनित्र जिसका अर्थ यह विचार करेंगे कोषगत है, 10की तुलना में कम होने के लिए 2के बाद से 1से भी कम है 2
कास्टल

@ 4castle ठीक है, मैंने कोड को अपडेट कर दिया है, लेकिन इसे वापस लाने जा रहा हूं: लेक्सिकोग्राफिक ऑर्डर और न्यूमेरिकल ऑर्डर के बीच का अंतर उस रेंज में संख्याओं के लिए मायने नहीं रखता है जो Math.random()उत्पादन करता है। (वह है, लेक्सिकोग्राफिक ऑर्डर न्यूमेरिक ऑर्डर के समान है जब 0 (समावेशी) से लेकर 1 (अनन्य) तक की संख्याओं के साथ व्यवहार किया जाता है
डैनियल मार्टिन

14
var shuffle = function(array) {
   temp = [];
   originalLength = array.length;
   for (var i = 0; i < originalLength; i++) {
     temp.push(array.splice(Math.floor(Math.random()*array.length),1));
   }
   return temp;
};

यह स्पष्ट रूप से फिशर-येट्स एल्गोरिथ्म के रूप में इष्टतम नहीं है, लेकिन क्या यह तकनीकी साक्षात्कार के लिए काम करेगा?
davidatthepark

@ और कोड इस तथ्य के कारण टूट गया था कि लूप के लिए सरणी की लंबाई बदल दी गई है। अंतिम संपादन के साथ यह सही हो गया है।
चार्ली वालेस

11
arr1.sort(() => Math.random() - 0.5);

1
माइनस 0.5 क्यों? उस संख्या का क्या अर्थ है?
सरथिस स्टॉर्महैमर

1
@SartherisStormhammer क्योंकि हम सॉर्ट के लिए एक तुलना का उपयोग कर रहे हैं, और यदि वह 0 से अधिक संख्या देता है, तो तुलना किए जा रहे तत्वों को केवल दिशा में आदेश दिया जाएगा। -0.5 मैथ.क्रैंड पर () हमें एक नकारात्मक संख्या देगा ~ 50% समय, जो हमें रिवर्स ऑर्डर देता है।
सैम डोज

सीधे आगे और सबसे सरल समाधान। धन्यवाद
deanwilliammills

9

आप इसे आसानी से कर सकते हैं:

// array
var fruits = ["Banana", "Orange", "Apple", "Mango"];
// random
fruits.sort(function(a, b){return 0.5 - Math.random()});
// out
console.log(fruits);

कृपया जावास्क्रिप्ट सॉर्टिंग एरे पर संदर्भ दें


यह एल्गोरिथ्म लंबे समय से दोषपूर्ण साबित हुआ है।

कृपया मुझे साबित करें। मैं w3schools पर आधारित हूं
Tính Ngô Quang

4
आपको कम से धागा पढ़ सकता है css-tricks.com/snippets/javascript/shuffle-array , या कम से news.ycombinator.com/item?id=2728914 । W3schools हमेशा से रहे हैं, और बनी हुई है, जानकारी का एक भयानक स्रोत है।

क्यों यह एक अच्छा दृष्टिकोण नहीं है पर एक अच्छी चर्चा के लिए देखें stackoverflow.com/questions/962802/…
चार्ली वालेस

8

एक पुनरावर्ती समाधान:

function shuffle(a,b){
    return a.length==0?b:function(c){
        return shuffle(a,(b||[]).concat(c));
    }(a.splice(Math.floor(Math.random()*a.length),1));
};

8

जावास्क्रिप्ट में फिशर-येट्स फेरबदल। मैं यहां यह पोस्ट कर रहा हूं क्योंकि दो उपयोगिता कार्यों (स्वैप और रैंडआईंट) का उपयोग यहां अन्य उत्तरों की तुलना में एल्गोरिदम को स्पष्ट करता है।

function swap(arr, i, j) { 
  // swaps two elements of an array in place
  var temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
}
function randInt(max) { 
  // returns random integer between 0 and max-1 inclusive.
  return Math.floor(Math.random()*max);
}
function shuffle(arr) {
  // For each slot in the array (starting at the end), 
  // pick an element randomly from the unplaced elements and
  // place it in the slot, exchanging places with the 
  // element in the slot. 
  for(var slot = arr.length - 1; slot > 0; slot--){
    var element = randInt(slot+1);
    swap(arr, element, slot);
  }
}

7

सबसे पहले, यहाँ एक नज़र है जावास्क्रिप्ट में विभिन्न छंटाई विधियों की एक महान दृश्य तुलना के लिए ।

दूसरी बात, अगर आपको ऊपर दिए गए लिंक पर एक त्वरित नज़र है तो आप पाएंगे कि random orderअन्य तरीकों की तुलना में यह क्रम अपेक्षाकृत अच्छा प्रदर्शन करता है, जबकि नीचे दिए गए अनुसार इसे लागू करना बेहद आसान और तेज़ है:

function shuffle(array) {
  var random = array.map(Math.random);
  array.sort(function(a, b) {
    return random[array.indexOf(a)] - random[array.indexOf(b)];
  });
}

संपादित करें : जैसा कि @gregers द्वारा बताया गया है, तुलना फ़ंक्शन सूचकांकों के बजाय मूल्यों के साथ कहा जाता है, यही कारण है कि आपको उपयोग करने की आवश्यकता है indexOf। ध्यान दें कि यह परिवर्तन indexOfO (n) समय में रन के रूप में बड़े सरणियों के लिए कोड को कम उपयुक्त बनाता है ।


Array.prototype.sortसूचकांक के रूप में और , दो मूल्यों में गुजरता है । तो यह कोड काम नहीं करता है। ab
ग्रेगर्स

@ आप सही हैं, मैंने उत्तर संपादित कर दिया है। धन्यवाद।
मिलो विलोन्डेक

1
यह बहुत यादृच्छिक नहीं है। सॉर्ट के कार्यान्वयन के आधार पर, सबसे कम इंडेक्स वाले तत्व को उच्चतम इंडेक्स के बगल वाले तत्व की तुलना में उच्चतम इंडेक्स में जाने के लिए अधिक तुलना की आवश्यकता हो सकती है। इसका मतलब यह है कि सबसे कम सूचकांक पर तत्व के उच्चतम सूचकांक पर पहुंचने की संभावना कम है।
1 'या 1 -

7

एक फेरबदल फ़ंक्शन जो स्रोत सरणी को नहीं बदलता है

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

मूल उत्तर:

यदि आप स्रोत सरणी को म्यूट करने के लिए अपने फेरबदल फ़ंक्शन की इच्छा नहीं रखते हैं , तो आप इसे एक स्थानीय चर में कॉपी कर सकते हैं, फिर एक साधारण फेरबदल तर्क के साथ आराम करें ।

function shuffle(array) {
  var result = [], source = array.concat([]);

  while (source.length) {
    let index = Math.floor(Math.random() * source.length);
    result.push(source[index]);
    source.splice(index, 1);
  }

  return result;
}

तर्क का फेरबदल : एक यादृच्छिक सूचकांक उठाएं , फिर परिणाम सरणी में संबंधित तत्व जोड़ें और इसे स्रोत सरणी प्रतिलिपि से हटा दें । स्रोत सरणी खाली होने तक इस क्रिया को दोहराएं

और अगर आप वास्तव में इसे कम चाहते हैं, तो यहां मुझे कितना दूर मिल सकता है:

function shuffle(array) {
  var result = [], source = array.concat([]);

  while (source.length) {
    let index = Math.floor(Math.random() * source.length);
    result.push(source.splice(index, 1)[0]);
  }

  return result;
}

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

@torazaburo, आपकी प्रतिक्रिया के लिए धन्यवाद। मैंने अपना उत्तर अपडेट कर दिया है, यह स्पष्ट करने के लिए कि मैं एक शानदार दिखने वाले समाधान की पेशकश कर रहा हूं, एक सुपर-स्केलिंग की तुलना में
एवगेनिया मनोलोवा

हम भी इस्तेमाल कर सकते हैं spliceतो तरह एक प्रतिलिपि बनाने के लिए विधि: source = array.slice();
तायगा


5

फ़िशर-येट्स का एक और कार्यान्वयन, सख्त मोड का उपयोग करके:

function shuffleArray(a) {
    "use strict";
    var i, t, j;
    for (i = a.length - 1; i > 0; i -= 1) {
        t = a[i];
        j = Math.floor(Math.random() * (i + 1));
        a[i] = a[j];
        a[j] = t;
    }
    return a;
}

स्वीकार किए गए उत्तर पर उपयोग के अतिरिक्त क्या मूल्य प्रदान करता है?
शॉर्टस्टफसुशी

सख्त मोड के बारे में अधिक जानने के लिए और यह प्रदर्शन को कैसे प्रभावित करता है, इसके बारे में आप यहाँ पढ़ सकते हैं: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
राफेल सी।

हम्म, क्या आप संदर्भित दस्तावेज़ से कुछ विशेष की ओर इशारा कर सकते हैं? वहाँ कुछ भी नहीं "संदर्भ में सुधार," एक अस्पष्ट टिप्पणी से अलग करने के लिए लगता है कि संभवत: जे एस इंजन के लिए अनुकूलन करने के लिए शीर्ष पर एक अस्पष्ट टिप्पणी। इस मामले में, मेरे लिए यह स्पष्ट नहीं है कि सख्त उपयोग से क्या सुधार होगा।
शॉर्टस्टफसुशी

सख्त मोड लगभग कुछ समय के लिए किया गया है, और वहाँ किसी को भी अपनी राय बनाने के लिए पर्याप्त पढ़े हुए हैं अगर उन्हें हमेशा इसका उपयोग करना चाहिए या नहीं और क्यों। उदाहरण के लिए Jslint यह स्पष्ट करता है कि आपको हमेशा सख्त मोड का उपयोग करना चाहिए। डगलस क्रॉफोर्ड ने काफी मात्रा में लेख और कुछ बेहतरीन वीडियो लिखे हैं कि क्यों हमेशा एक अच्छी प्रैक्टिस के रूप में न केवल सख्त मोड का उपयोग करना महत्वपूर्ण है, बल्कि यह वी 8 जैसे ब्राउज़र जेएस इंजनों द्वारा अलग तरीके से कैसे व्याख्या की जाती है। मैं आपको Google को इसकी दृढ़ता से सलाह देता हूं और इसके बारे में अपनी राय बनाता हूं।
राफेल सी

यहाँ सख्त मोड में perfs के बारे में एक पुराना धागा है, थोड़ा पुराना है लेकिन अभी भी प्रासंगिक है: stackoverflow.com/questions/3145966/…
राफेल सी

5

अन्य सभी उत्तर Math.random () पर आधारित हैं जो तेज है लेकिन क्रिप्टोग्राफिक स्तर के यादृच्छिकरण के लिए उपयुक्त नहीं है।

यादृच्छिकता के क्रिप्टोग्राफिक स्तर काFisher-Yates उपयोग करते हुए नीचे दिए कोड अच्छी तरह से ज्ञात एल्गोरिथ्म का उपयोग कर Web Cryptography APIरहे हैं ।

var d = [1,2,3,4,5,6,7,8,9,10];

function shuffle(a) {
	var x, t, r = new Uint32Array(1);
	for (var i = 0, c = a.length - 1, m = a.length; i < c; i++, m--) {
		crypto.getRandomValues(r);
		x = Math.floor(r / 65536 / 65536 * m) + i;
		t = a [i], a [i] = a [x], a [x] = t;
	}

	return a;
}

console.log(shuffle(d));


4

ES6 सुविधाओं का उपयोग करते हुए आधुनिक लघु इनलाइन समाधान:

['a','b','c','d'].map(x => [Math.random(), x]).sort(([a], [b]) => a - b).map(([_, x]) => x);

(शैक्षिक उद्देश्यों के लिए)


4

CoolAJ86 के उत्तर का एक सरल संशोधन जो मूल सरणी को संशोधित नहीं करता है:

 /**
 * Returns a new array whose contents are a shuffled copy of the original array.
 * @param {Array} The items to shuffle.
 * https://stackoverflow.com/a/2450976/1673761
 * https://stackoverflow.com/a/44071316/1673761
 */
const shuffle = (array) => {
  let currentIndex = array.length;
  let temporaryValue;
  let randomIndex;
  const newArray = array.slice();
  // While there remains elements to shuffle...
  while (currentIndex) {
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;
    // Swap it with the current element.
    temporaryValue = newArray[currentIndex];
    newArray[currentIndex] = newArray[randomIndex];
    newArray[randomIndex] = temporaryValue;
  }
  return newArray;
};

4

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

var myArr = ["a", "b", "c", "d"];

myArr.forEach((val, key) => {
  randomIndex = Math.ceil(Math.random()*(key + 1));
  myArr[key] = myArr[randomIndex];
  myArr[randomIndex] = val;
});
// see the values
console.log('Shuffled Array: ', myArr)

4

बस पाई में उंगली करनी है। यहाँ मैं फिशर येट्स फेरबदल (मुझे लगता है) का एक पुनरावर्ती कार्यान्वयन प्रस्तुत करता है। यह एक समान यादृच्छिकता देता है।

नोट: ~~(डबल टिल्ड ऑपरेटर) वास्तव में Math.floor()सकारात्मक वास्तविक संख्याओं की तरह व्यवहार करता है । बस एक छोटा सा कट है।

var shuffle = a => a.length ? a.splice(~~(Math.random()*a.length),1).concat(shuffle(a))
                            : a;

console.log(JSON.stringify(shuffle([0,1,2,3,4,5,6,7,8,9])));

संपादित करें: उपरोक्त कोड O (n ^ 2) है, .splice()लेकिन रोजगार के कारण हम स्वैप चाल से O (n) में विभाजन और फेरबदल को समाप्त कर सकते हैं।

var shuffle = (a, l = a.length, r = ~~(Math.random()*l)) => l ? ([a[r],a[l-1]] = [a[l-1],a[r]], shuffle(a, l-1))
                                                              : a;

var arr = Array.from({length:3000}, (_,i) => i);
console.time("shuffle");
shuffle(arr);
console.timeEnd("shuffle");

समस्या यह है कि, जेएस बड़े पुनरावृत्तियों के साथ सहयोग नहीं कर सकता है। इस विशेष स्थिति में आपके ब्राउजर इंजन और कुछ अज्ञात तथ्यों के आधार पर सरणी का आकार 3000 ~ 7000 तक सीमित है।


3

सरणी को यादृच्छिक करें

 var arr = ['apple','cat','Adam','123','Zorro','petunia']; 
 var n = arr.length; var tempArr = [];

 for ( var i = 0; i < n-1; i++ ) {

    // The following line removes one random element from arr 
     // and pushes it onto tempArr 
     tempArr.push(arr.splice(Math.floor(Math.random()*arr.length),1)[0]);
 }

 // Push the remaining item onto tempArr 
 tempArr.push(arr[0]); 
 arr=tempArr; 

वहाँ नहीं होना चाहिए एक -1n के रूप में आप का इस्तेमाल <नहीं किया<=
Mohebifar


3

सैद्धांतिक दृष्टिकोण से, इसे करने का सबसे सुरुचिपूर्ण तरीका, मेरी विनम्र राय में, 0 और n -- 1 के बीच एक एकल यादृच्छिक संख्या प्राप्त करना और एक से एक मैपिंग की गणना करना है । जब तक आप एक (छद्म-) यादृच्छिक जनरेटर का उपयोग कर सकते हैं, बिना किसी महत्वपूर्ण पूर्वाग्रह के इस तरह के एक नंबर को प्राप्त करने के लिए पर्याप्त विश्वसनीय है, तो आपके पास कई अन्य यादृच्छिक संख्याओं की आवश्यकता के बिना प्राप्त करने के लिए इसमें पर्याप्त जानकारी है।{0, 1, …, n!-1}(0, 1, 2, …, n-1)

IEEE754 डबल सटीक फ़्लोटिंग संख्याओं के साथ गणना करते समय, आप अपने यादृच्छिक जनरेटर से लगभग 15 डेसीमल की उम्मीद कर सकते हैं। चूँकि आपके पास 15! = 1,307,674,368,000 (13 अंकों के साथ) हैं, तो आप निम्न कार्यों का उपयोग 15 तत्वों वाले सरणियों के साथ कर सकते हैं और मान सकते हैं कि 14 तत्वों वाले सरणियों के साथ कोई महत्वपूर्ण पूर्वाग्रह नहीं होगा। यदि आप एक निश्चित आकार की समस्या पर काम करते हैं, तो इस फेरबदल ऑपरेशन को कई बार गणना करने की आवश्यकता होती है, तो आप निम्नलिखित कोड को आज़माना चाह सकते हैं जो अन्य कोडों की तुलना में तेज़ हो सकता है क्योंकि यह Math.randomकेवल एक बार उपयोग करता है (इसमें कई कॉपी ऑपरेशन शामिल हैं)।

निम्नलिखित फ़ंक्शन का उपयोग नहीं किया जाएगा, लेकिन मैं इसे वैसे भी देता हूं; यह (0, 1, 2, …, n-1)इस संदेश में उपयोग की जाने वाली एक से एक मैपिंग के अनुसार दिए गए क्रमबद्धता के सूचकांक को लौटाता है (क्रमपरिवर्तन करते समय सबसे प्राकृतिक एक); यह 16 तत्वों के साथ काम करने का इरादा है:

function permIndex(p) {
    var fact = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000];
    var tail = [];
    var i;
    if (p.length == 0) return 0;
    for(i=1;i<(p.length);i++) {
        if (p[i] > p[0]) tail.push(p[i]-1);
        else tail.push(p[i]);
    }
    return p[0] * fact[p.length-1] + permIndex(tail);
}

पिछले फ़ंक्शन का पारस्परिक (अपने स्वयं के प्रश्न के लिए आवश्यक) नीचे है; इसका उद्देश्य 16 तत्वों के साथ काम करना है; यह आदेश n के क्रमचय को लौटाता है (0, 1, 2, …, s-1):

function permNth(n, s) {
    var fact = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000];
    var i, j;
    var p = [];
    var q = [];
    for(i=0;i<s;i++) p.push(i);
    for(i=s-1; i>=0; i--) {
        j = Math.floor(n / fact[i]);
        n -= j*fact[i];
        q.push(p[j]);
        for(;j<i;j++) p[j]=p[j+1];
    }
    return q;
}

अब, आप क्या चाहते हैं:

function shuffle(p) {
    var fact = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000];
    return permNth(Math.floor(Math.random()*fact[p.length]), p.length).map(
            function(i) { return p[i]; });
}

इसे थोड़ा सैद्धांतिक पूर्वाग्रह के साथ 16 तत्वों तक काम करना चाहिए (हालांकि व्यावहारिक दृष्टिकोण से ध्यान देने योग्य नहीं है); यह 15 तत्वों के लिए पूरी तरह से प्रयोग करने योग्य के रूप में देखा जा सकता है; 14 से कम तत्वों वाले सरणियों के साथ, आप सुरक्षित रूप से विचार कर सकते हैं कि कोई पूर्वाग्रह नहीं होगा।


निश्चित रूप से सुरुचिपूर्ण!
गेरशोम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.