मेरे पास एक सरणी है:
var arr1 = ["a", "b", "c", "d"];
मैं इसे कैसे यादृच्छिक / फेरबदल कर सकता हूं?
मेरे पास एक सरणी है:
var arr1 = ["a", "b", "c", "d"];
मैं इसे कैसे यादृच्छिक / फेरबदल कर सकता हूं?
जवाबों:
डी-फैक्टो निष्पक्ष फेरबदल एल्गोरिथ्म फिशर-येट्स (उर्फ नूथ) शफल है।
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);
उपयोग किए गए एल्गोरिथ्म के बारे में कुछ और जानकारी ।
i--
नहीं होनी चाहिए --i
। इसके अलावा, जब तक लूप कभी भी प्रवेश नहीं किया जाएगा , तब से परीक्षण if (i==0)...
बहुत ही i == 0
शानदार है । कॉल का उपयोग तेजी से किया जा सकता है । भीMath.floor
...| 0
टेम्पाई या tempj हटाया जा सकता है और मूल्य सीधे को सौंपा जा myArray [i] या जे के रूप में उपयुक्त।
0 !== currentIndex
)।
यहां डर्स्टनफील्ड फेरबदल का एक जावास्क्रिप्ट कार्यान्वयन , फिशर-येट्स का एक अनुकूलित संस्करण है:
/* 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)
।
नया 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]];
}
}
return array
फ़ंक्शन तर्कों के रूप में उपयोग किए जाने के बाद जावास्क्रिप्ट को संदर्भों से पास होने की आवश्यकता नहीं है। मुझे लगता है कि यह स्टैक स्पेस को बचाने के लिए है, लेकिन यह एक छोटी सी विशेषता है। सरणी पर फेरबदल करना मूल सरणी को फेरबदल करेगा।
Math.random() should not be multiplied with the loop counter + 1, but with
array.lengt () `। एक विशिष्ट श्रेणी में जावास्क्रिप्ट में यादृच्छिक पूर्ण संख्या उत्पन्न करना देखें ? बहुत व्यापक व्याख्या के लिए।
चेतावनी!
इस एल्गोरिथ्म के उपयोग की अनुशंसा नहीं की जाती है , क्योंकि यह अक्षम और दृढ़ता से पक्षपाती है ; टिप्पणी देखो। इसे भविष्य के संदर्भ के लिए यहां छोड़ दिया जा रहा है, क्योंकि यह विचार उतना दुर्लभ नहीं है।
[1,2,3,4,5,6].sort(function() {
return .5 - Math.random();
});
एक (या) यह ऐरे से एक प्रोटॉयपे के रूप में उपयोग कर सकता है:
क्रिस्टोफ़ से:
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;
}
for...in
सरणियों पर पुनरावृति करने के लिए छोरों का उपयोग न करें ।
आप इसे आसानी से मानचित्र और सॉर्ट के साथ कर सकते हैं:
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)
आप बहुरंगी सरणियों को फेरबदल कर सकते हैं, और यह छांटना Math.random की तरह यादृच्छिक है, जो अधिकांश उद्देश्यों के लिए पर्याप्त है।
चूंकि तत्वों को लगातार कुंजियों के खिलाफ क्रमबद्ध किया जाता है जो प्रत्येक पुनरावृत्ति को पुनर्जीवित नहीं करते हैं, और प्रत्येक तुलना समान वितरण से खींचती है, Math.random के वितरण में किसी भी गैर-यादृच्छिकता को रद्द कर दिया जाता है।
गति
समय जटिलता ओ (एन लॉग एन) है, जो त्वरित सॉर्ट के समान है। अंतरिक्ष जटिलता O (N) है। यह एक फिशर येट्स फेरबदल के रूप में कुशल नहीं है लेकिन, मेरी राय में, कोड काफी छोटा और अधिक कार्यात्मक है। यदि आपके पास एक बड़ा सरणी है तो आपको निश्चित रूप से फिशर येट्स का उपयोग करना चाहिए। यदि आपके पास कुछ सौ वस्तुओं के साथ एक छोटा सा सरणी है, तो आप ऐसा कर सकते हैं।
अंडरस्कोर .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();
shuffle
फ़ंक्शन प्राप्त करने के लिए पूरी लाइब्रेरी को शामिल करने का कोई मतलब नहीं है ।
नया!
कम और शायद * तेज फिशर-येट्स फेरबदल एल्गोरिथ्म
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
}
}
fy
और shuffle prototype
, मैं मिल fy
पर ओएस एक्स 10.9.5 क्रोम 37 में नीचे (81% धीमी ~ ~ 100k की तुलना में 20k ऑप्स) और सफारी 7.1 पर लगातार यह 8% धीमी ~ पर निर्भर है। YMMV, लेकिन यह हमेशा तेज़ नहीं होता है। jsperf.com/fyshuffle/3
संपादित करें: यह उत्तर गलत है
टिप्पणियाँ और 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>
इस पृष्ठ पर कुछ समाधान विश्वसनीय नहीं हैं (वे केवल सरणी को आंशिक रूप से यादृच्छिक करते हैं)। अन्य समाधान काफी कम कुशल हैं। साथ testShuffleArrayFun
(नीचे देखें) हम विश्वसनीयता और प्रदर्शन के लिए सरणी फेरबदल कार्यों का परीक्षण कर सकते हैं। निम्नलिखित समाधान हैं: विश्वसनीय, कुशल और संक्षिप्त (ES6 सिंटैक्स का उपयोग करके)
[ testShuffleArrayFun
Google 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]
)
}
[array[i], array[rand]]=[array[rand], array[i]]
? शायद आप इस बात को रेखांकित कर सकते हैं कि यह कैसे काम करता है। आप नीचे की ओर पुनरावृति क्यों चुनते हैं?
@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
};
var b =
बाहरी लूप घोषित करने के बजाय लूप में करने के लिए कुशल है और इसे लूप में असाइन करना है b =
?
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
एक यादृच्छिक संख्या है जो सकारात्मक या नकारात्मक हो सकती है, इसलिए छँटाई फ़ंक्शन यादृच्छिक तत्वों को पुन: व्यवस्थित करता है।
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();
n >>> 0
इसके बजाय का उपयोग करना चाहिए ~~n
। ऐरे इंडेक्स 2 be-1 से अधिक हो सकते हैं।
मुझे इस प्रश्न के डुप्लिकेट पर "लेखक द्वारा हटाए गए" उत्तर में यह संस्करण लटका हुआ मिला। कुछ अन्य उत्तरों के विपरीत जिनमें पहले से ही कई उतार-चढ़ाव हैं, यह है:
shuffled
नाम के बजाय shuffle
)यहाँ एक jsfiddle यह उपयोग में दिखा रहा है ।
Array.prototype.shuffled = function() {
return this.map(function(n){ return [Math.random(), n] })
.sort().map(function(n){ return n[1] });
}
[1,2,3,4,5,6].sort(function() { return .5 - Math.random(); });
- यह एक यादृच्छिक प्रकार नहीं देता है, और यदि आप इसका उपयोग करते हैं तो आप शर्मिंदा हो सकते हैं: robweir.com/blog/2010/02/microsoft-random-browser-ballot.html
.sort(function(a,b){ return a[0] - b[0]; })
यदि आप क्रमबद्ध रूप से मानों की तुलना करना चाहते हैं तो आपको इसका उपयोग करने की आवश्यकता है । डिफ़ॉल्ट .sort()
तुलनित्र जिसका अर्थ यह विचार करेंगे कोषगत है, 10
की तुलना में कम होने के लिए 2
के बाद से 1
से भी कम है 2
।
Math.random()
उत्पादन करता है। (वह है, लेक्सिकोग्राफिक ऑर्डर न्यूमेरिक ऑर्डर के समान है जब 0 (समावेशी) से लेकर 1 (अनन्य) तक की संख्याओं के साथ व्यवहार किया जाता है
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;
};
arr1.sort(() => Math.random() - 0.5);
आप इसे आसानी से कर सकते हैं:
// array
var fruits = ["Banana", "Orange", "Apple", "Mango"];
// random
fruits.sort(function(a, b){return 0.5 - Math.random()});
// out
console.log(fruits);
कृपया जावास्क्रिप्ट सॉर्टिंग एरे पर संदर्भ दें
जावास्क्रिप्ट में फिशर-येट्स फेरबदल। मैं यहां यह पोस्ट कर रहा हूं क्योंकि दो उपयोगिता कार्यों (स्वैप और रैंडआईंट) का उपयोग यहां अन्य उत्तरों की तुलना में एल्गोरिदम को स्पष्ट करता है।
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);
}
}
सबसे पहले, यहाँ एक नज़र है जावास्क्रिप्ट में विभिन्न छंटाई विधियों की एक महान दृश्य तुलना के लिए ।
दूसरी बात, अगर आपको ऊपर दिए गए लिंक पर एक त्वरित नज़र है तो आप पाएंगे कि 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
। ध्यान दें कि यह परिवर्तन indexOf
O (n) समय में रन के रूप में बड़े सरणियों के लिए कोड को कम उपयुक्त बनाता है ।
Array.prototype.sort
सूचकांक के रूप में और , दो मूल्यों में गुजरता है । तो यह कोड काम नहीं करता है। a
b
अपडेट : यहां मैं एक अपेक्षाकृत सरल ( जटिलता के दृष्टिकोण से नहीं ) और छोटे एल्गोरिदम का सुझाव दे रहा हूं जो छोटे आकार के सरणियों के साथ ठीक करेंगे, लेकिन जब आप विशाल सरणियों से निपटते हैं तो निश्चित रूप से क्लासिक डर्स्टनफील्ड एल्गोरिदम की तुलना में बहुत अधिक खर्च होता है । आप इस प्रश्न के शीर्ष उत्तरों में से एक में डर्स्टनफील्ड पा सकते हैं ।
मूल उत्तर:
यदि आप स्रोत सरणी को म्यूट करने के लिए अपने फेरबदल फ़ंक्शन की इच्छा नहीं रखते हैं , तो आप इसे एक स्थानीय चर में कॉपी कर सकते हैं, फिर एक साधारण फेरबदल तर्क के साथ आराम करें ।
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
भयानक रूप से अक्षम करने के तरीके के साथ जो उन्होंने "स्ट्राइक आउट" कहा। यदि आप मूल सरणी को म्यूट नहीं करना चाहते हैं, तो बस इसे कॉपी करें, और फिर उस प्रतिलिपि को बहुत अधिक कुशल डर्स्टनफील्ड संस्करण का उपयोग करके जगह में फेरबदल करें।
splice
तो तरह एक प्रतिलिपि बनाने के लिए विधि: source = array.slice();
।
यहाँ एक आसान है,
function shuffle(array) {
array.sort(() => Math.random() - 0.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;
}
अन्य सभी उत्तर 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));
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;
};
हालाँकि, पहले से ही लागू किए गए कई कार्यान्वयन हैं, लेकिन मुझे लगता है कि हम इसे फॉर्च लूप का उपयोग करके कम और आसान बना सकते हैं, इसलिए हमें सरणी लंबाई की गणना करने के बारे में चिंता करने की आवश्यकता नहीं है और हम अस्थायी चर का उपयोग करने से भी सुरक्षित रूप से बच सकते हैं।
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)
बस पाई में उंगली करनी है। यहाँ मैं फिशर येट्स फेरबदल (मुझे लगता है) का एक पुनरावर्ती कार्यान्वयन प्रस्तुत करता है। यह एक समान यादृच्छिकता देता है।
नोट: ~~
(डबल टिल्ड ऑपरेटर) वास्तव में 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 तक सीमित है।
सरणी को यादृच्छिक करें
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;
-1
n के रूप में आप का इस्तेमाल <
नहीं किया<=
सबसे छोटा arrayShuffle
कार्य
function arrayShuffle(o) {
for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
}
सैद्धांतिक दृष्टिकोण से, इसे करने का सबसे सुरुचिपूर्ण तरीका, मेरी विनम्र राय में, 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 से कम तत्वों वाले सरणियों के साथ, आप सुरक्षित रूप से विचार कर सकते हैं कि कोई पूर्वाग्रह नहीं होगा।