මට මේ වගේ අරාවක් තියෙනවා:
var arr1 = ["a", "b", "c", "d"];
මම එය අහඹු ලෙස වෙනස් කරන්නේ කෙසේද?
මට මේ වගේ අරාවක් තියෙනවා:
var arr1 = ["a", "b", "c", "d"];
මම එය අහඹු ලෙස වෙනස් කරන්නේ කෙසේද?
Answers:
තථ්ය අපක්ෂපාතී ෂෆල් ඇල්ගොරිතම වන්නේ ෆිෂර්-යේට්ස් (නො නුත්) ෂෆල් ය.
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
. එක්කෝ tempi හෝ tempj ඉවත් කළ හැකි අතර, වටිනාකම කෙලින්ම සඳහා අනුයුක්ත කරනු [i] myArray හෝ j සුදුසු පරිදි.
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();
});
සිතියම සහ වර්ග කිරීම සමඟ ඔබට එය පහසුවෙන් කළ හැකිය:
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 log N), ඉක්මන් වර්ග කිරීමකට සමානය. අභ්යවකාශ සංකීර්ණතාව O (N) වේ. මෙය ෆිෂර් යේට්ස් මාරුව තරම් කාර්යක්ෂම නොවන නමුත් මගේ මතය අනුව කේතය සැලකිය යුතු ලෙස කෙටි හා වඩා ක්රියාකාරී වේ. ඔබට විශාල අරාවක් තිබේ නම් ඔබ නිසැකවම ෆිෂර් යේට්ස් භාවිතා කළ යුතුය. ඔබට අයිතම සිය ගණනක් සහිත කුඩා අරාවක් තිබේ නම්, ඔබට මෙය කළ හැකිය.
කෙනෙකුට එය අරේ වෙතින් ප්රෝටෝනයක් ලෙස භාවිතා කළ හැකිය (හෝ කළ යුතුය):
ක්රිස්ටෝෆෙඩ් වෙතින්:
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
අරා හරහා නැවත ධාවනය කිරීමට ලූප භාවිතා නොකරන්න .
Undererscore.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 සමඟ ක්රියාකාරී නම ලෙස): බයිට් 90
ඩෙමෝ http://jsfiddle.net/vvpoma8w/
* ක්රෝම් හැර අනෙකුත් සියලුම බ්රව්සර් වල වේගවත් වේ.
ඔබට කිසියම් ප්රශ්නයක් ඇත්නම් විමසන්න.
සංස්කරණය කරන්න
ඔව් එය වේගවත්
කාර්යසාධනය: http://jsperf.com/fyshuffle
ඉහළ ඡන්දය දුන් කාර්යයන් භාවිතා කිරීම.
සංස්කරණය කරන්න අතිරික්ත ගණනය කිරීමක් සිදු විය (--c + 1 අවශ්ය නොවේ) සහ කිසිවෙකු නොදැන සිටියේය
කෙටි (බයිට් 4) සහ වේගවත් (එය පරීක්ෂා කරන්න!).
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/
කියවිය හැකි අනුවාදය (මුල් අනුවාදය භාවිතා කරන්න. මෙය මන්දගාමී ය, වැර්ස් නිෂ් less ල ය, වසා දැමීම් මෙන් & ";", කේතය ද කෙටි ය ... සමහර විට මෙය කියවන්න ජාවාස්ක්රිප්ට් කේතය 'අවම කරන්නේ කෙසේද', 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
OS X මෙහෙයුම් පද්ධතිය 10.9.5 (81% මන්දගාමී ~ 100k සාපේක්ෂව ~ 20k මෙහෙයුම්) සහ සෆාරි 7.1 මත Chrome 37 පතුලේ නිරතුරුවම එය ~ 8% මන්දගාමී වෙලා තියෙන්නේ. YMMV, නමුත් එය සැමවිටම වේගවත් නොවේ. jsperf.com/fyshuffle/3
අරා මාරු කරන්න
function shuffleArr (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]]
}
}
ES6 පිරිසිදු, අනුකාරක
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
};
විශ්වසනීයත්වය සහ කාර්ය සාධන පරීක්ෂණය
මෙම පිටුවේ ඇති සමහර විසඳුම් විශ්වාසදායක නොවේ (ඒවා අර්ධ වශයෙන් පමණක් අරාව අහඹු කරයි). වෙනත් විසඳුම් සැලකිය යුතු ලෙස අඩු කාර්යක්ෂම වේ. සමග testShuffleArrayFun
(පහත බලන්න) අපි විශ්වසනීයත්වය සහ කාර්ය සාධනය සඳහා අරා අවුල් කාර්යයන් පරීක්ෂා කළ හැක.
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}`)
}
විනෝදය සඳහා පමණක් වෙනත් විසඳුම්.
ES6 පිරිසිදු, පුනරාවර්තන
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))];
};
Array.map භාවිතා කරමින් ES6 පිරිසිදු
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]
})
}
Array.reduce භාවිතා කරමින් ES6 පිරිසිදු
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]]
? සමහර විට ඔබට එය ක්රියාත්මක වන ආකාරය ගෙනහැර දැක්විය හැකිය. ඔබ පහළට නැවත යෙදීමට තෝරා ගන්නේ ඇයි?
සංස්කරණය කරන්න: මෙම පිළිතුර වැරදිය
අදහස් සහ https://stackoverflow.com/a/18650169/28234 බලන්න . අදහස දුර්ලභ නොවන නිසා එය යොමු කිරීම සඳහා මෙහි තබනු ලැබේ.
කුඩා අරා සඳහා ඉතා සරල ක්රමයක් මෙයයි:
const someArray = [1, 2, 3, 4, 5];
someArray.sort(() => Math.random() - 0.5);
එය බොහෝ විට ඉතා කාර්යක්ෂම නොවේ, නමුත් කුඩා අරා සඳහා මෙය හොඳින් ක්රියාත්මක වේ. මෙන්න එය උදාහරණයක් ලෙස ඔබට එය අහඹු ලෙස (හෝ නැත) සහ එය ඔබගේ භාවිතයට ගැලපෙනවාද නැද්ද යන්න දැක ගත හැකිය.
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>
A ලෝරන්ස් හෝල්ස්ට් පිළිතුරට එකතු කිරීම. මෙය 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
අහඹු සංඛ්යාවක් ධනාත්මක හෝ negative ණ විය හැකි බැවින් වර්ග කිරීමේ ශ්රිතය අහඹු ලෙස මූලද්රව්ය නැවත සකස් කරයි.
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³¹-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()
comparator තේරුම සලකා, lexicographic වේ 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);
මෙන්න පහසුම එක,
function shuffle(array) {
return array.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);
ෆිෂර්-යේට්ස් ජාවාස්ක්රිප්ට් වල මාරු වීම. මම මෙය මෙහි පළ කරන්නේ උපයෝගීතා ශ්රිත දෙකක් (swap සහ randInt) භාවිතා කිරීම මෙහි ඇති අනෙක් පිළිතුරු හා සසඳන විට ඇල්ගොරිතම පැහැදිලි කරන බැවිනි.
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)];
});
}
සංස්කරණය කරන්න : g ග්රෙගර්ස් පෙන්වා දුන් පරිදි, සංසන්දනය කිරීමේ ශ්රිතය දර්ශකවලට වඩා අගයන් සමඟ හැඳින්වේ, එබැවින් ඔබ භාවිතා කළ 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;
}
මාරුවීමේ තර්කනය : අහඹු දර්ශකයක් තෝරාගෙන ප්රති 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 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 සඳහා a නොතිබිය යුතුය<=
කෙටිම 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 ට වඩා අඩුවෙන් අඩංගු අරා සමඟ, කිසිදු නැඹුරුවක් නැති බව ඔබට ආරක්ෂිතව සලකා බැලිය හැකිය.