ජාවාස්ක්‍රිප්ට් අරාව අහඹු ලෙස (මාරු කිරීම) කරන්නේ කෙසේද?


1292

මට මේ වගේ අරාවක් තියෙනවා:

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

මම එය අහඹු ලෙස වෙනස් කරන්නේ කෙසේද?



6
: යන්තම් මේ මෙතන වීසි ඔබ කලවම් කාර්යය ඇත්තටම මේ විෂුවලයිසර් මයික් Bostock සමග කෙතරම් අහඹු සිදු හිතේ මවාගන්න පුළුවන් බව bost.ocks.org/mike/shuffle/compare.html
අගෝස්තු

5
LaBlazemonger jsPref මියගොස් ඇත. ඔබට වේගවත්ම දේ මෙහි පළ කළ හැකිද?
eozzy

එක් ලයිනර් ගැන කුමක් කිව හැකිද? ආපසු ලබා දුන් අරාව මාරු කර ඇත. arr1.reduce ((a, v) => a.splice (Math.floor (Math.random () * a.length), 0, v) && a, [])
brunettdan

අඩු කිරීමේ විසඳුමට O (n ^ 2) සංකීර්ණතාවයක් ඇත. මූලද්‍රව්‍ය මිලියනයක් සහිත අරාව මත එය ධාවනය කිරීමට උත්සාහ කරන්න.
riv

Answers:


1591

තථ්‍ය අපක්ෂපාතී ෂෆල් ඇල්ගොරිතම වන්නේ ෆිෂර්-යේට්ස් (නො නුත්) ෂෆල් ය.

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. එක්කෝ tempi හෝ tempj ඉවත් කළ හැකි අතර, වටිනාකම කෙලින්ම සඳහා අනුයුක්ත කරනු [i] myArray හෝ j සුදුසු පරිදි.
RobG

23
roprometheus, මිල අධික දෘඩාංග සමඟ සම්බන්ධ නොවන්නේ නම් සියලුම RNGs ව්‍යාජ සසම්භාවී වේ.
ෆිල් එච්

40
ඉහත ක්‍රියාත්මක කිරීම ක්‍රියාකාරීව නිවැරදි ය. ෆිෂර්-යේට්ස් ඇල්ගොරිතමයේ, ලූපය අරාවෙහි පළමු අංගය සඳහා ධාවනය කිරීමට අදහස් නොකෙරේ. පළමු අංගය මඟ හැරෙන වෙනත් ක්‍රියාත්මක කිරීම් ඇති විකිපීඩියාව බලන්න . පළමු මූලද්‍රව්‍යය සඳහා ලූපය ක්‍රියාත්මක නොවීම වැදගත් වන්නේ ඇයිද යන්න ගැන කතා කරන මෙම ලිපියද බලන්න.
තියොන්

35
නිකොලා "අහඹු ලෙස නොවේ" මට තරමක් ශක්තිමත් සුදුසුකමක් ඇත. ඔබ ගුප්ත ලේඛන ශිල්පියෙකු නොවන්නේ නම් එය ප්‍රමාණවත් තරම් අහඹු යැයි මම තර්ක කරමි, එවැනි අවස්ථාවක ඔබ බොහෝ විට Math.Random () භාවිතා නොකරනු ඇත.
toon81

22
අහ්, යෝඩා ( 0 !== currentIndex).
ffxsam

764

ෆිෂර්-යේට්ස් හි ප්‍රශස්තිකරණය කළ ඩර්ස්ටන්ෆෙල්ඩ් ෂෆල්හි ජාවාස්ක්‍රිප්ට් ක්‍රියාත්මක කිරීම මෙන්න :

/* 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 / 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
වේලාවකින්

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

144

අවවාදයයි!
මෙම ඇල්ගොරිතම භාවිතා කිරීම නිර්දේශ නොකරයි , මන්ද එය අකාර්යක්ෂම හා දැඩි ලෙස පක්ෂග්‍රාහී ය ; අදහස් බලන්න. අදහස එතරම් දුර්ලභ නොවන නිසා එය අනාගත යොමු කිරීම සඳහා මෙහි තබනු ලැබේ.

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

13
මම මෙම විසඳුමට කැමතියි, මූලික අහඹු ලෙස දීමට ප්‍රමාණවත්
ඇලෙක්ස් කේ

151
මෙය අඩු කිරීම ඇත්තෙන්ම අහඹු දෙයක් නොවේ. මම දන්නේ නැහැ ඇයි මෙතරම් ඉහළ නැගීම් තිබෙන්නේ කියලා. මෙම ක්රමය භාවිතා නොකරන්න. එය ලස්සනයි, නමුත් සම්පූර්ණයෙන්ම නිවැරදි නැහැ. ඔබගේ අරාවෙහි එක් එක් සංඛ්‍යා දර්ශකයට කොපමණ වාර ගණනක් පහර දෙන්නේද යන්න පිළිබඳ පුනරාවර්තන 10,000 කට පසුව ප්‍රති results ල මෙන්න (0] (මට අනෙක් ප්‍රති results ල ද ලබා දිය හැකිය): 1 = 29.19%, 2 = 29.53%, 3 = 20.06%, 4 = 11.91%, 5 = 5.99%, 6 = 3.32%
radtad

8
ඔබට සාපේක්ෂව කුඩා අරා අහඹු ලෙස කිරීමට අවශ්‍ය නම් සහ ගුප්ත ලේඛන දේවල් සමඟ කටයුතු නොකිරීම හොඳයි. ඔබට වඩාත් අහඹු ලෙස අවශ්‍ය නම් වඩාත් සංකීර්ණ විසඳුමක් භාවිතා කළ යුතු බව මම සම්පූර්ණයෙන්ම එකඟ වෙමි .
deadrunk


12
ගැටළුව වන්නේ එය නිර්ණායක නොවන අතර එය වැරදි ප්‍රති results ල ලබා දෙනු ඇත (1> 2 සහ 2> 3 නම්, එය 1> 3 ලබා දිය යුතුය, නමුත් මෙය සහතික නොකරයි. මෙය වර්ග කිරීම ව්‍යාකූල කර ප්‍රති result ලය අදහස් දක්වන්න @radtad විසින්).
MatsLindh

82

සිතියම සහ වර්ග කිරීම සමඟ ඔබට එය පහසුවෙන් කළ හැකිය:

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 log N), ඉක්මන් වර්ග කිරීමකට සමානය. අභ්‍යවකාශ සංකීර්ණතාව O (N) වේ. මෙය ෆිෂර් යේට්ස් මාරුව තරම් කාර්යක්ෂම නොවන නමුත් මගේ මතය අනුව කේතය සැලකිය යුතු ලෙස කෙටි හා වඩා ක්‍රියාකාරී වේ. ඔබට විශාල අරාවක් තිබේ නම් ඔබ නිසැකවම ෆිෂර් යේට්ස් භාවිතා කළ යුතුය. ඔබට අයිතම සිය ගණනක් සහිත කුඩා අරාවක් තිබේ නම්, ඔබට මෙය කළ හැකිය.


1
up සුපර්ලුමිනරි අපොයි, ඔබ හරි. සිටින බව දැනුම් මෙම පිළිතුර ප්රවිෂ්ටය ම දැනටමත් භාවිතා වේ.
බර්ගි

Er බර්ගි - ආ ඔව්, ඔබ හරි, මම හිතන්නේ මගේ ක්‍රියාත්මක කිරීම තරමක් ලස්සනයි.
සුපර්ලුමිනරි

3
ඉතා කදිමයි. මේ වන Schwartzian පරිණාමනය JS දී.
මාර්ක් ග්‍රීම්ස්

oratorazaburo - එය ෆිෂර් යේට්ස් තරම් කාර්ය සාධනයක් නොවේ, නමුත් එය මනරම් වන අතර කේතය කුඩා වේ. කේතය සැමවිටම වෙළඳාමකි. මට විශාල පෙළක් තිබේ නම්, මම නුත් භාවිතා කරමි. මා සතුව අයිතම සිය ගණනක් තිබේ නම්, මම මෙය කරන්නෙමි.
superluminary

2
En බෙන්කාර්ප් - එකඟ විය, එය වේගවත්ම විසඳුම නොවන අතර එය දැවැන්ත අරාවකට භාවිතා කිරීමට ඔබට අවශ්‍ය නොවනු ඇත, නමුත් අමු වේගයට වඩා කේතයේ වැඩි සැලකිල්ලක් ඇත.
සුපර්ලුමිනරි

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
ස්වදේශික මූලාකෘති
දීර් ing

12
ඔබ මෙය නොකළ යුතුය; මෙයින් බලපෑමට ලක්වන සෑම අරා එකක්ම ... in සඳහා ආරක්ෂිතව නැවත යෙදිය නොහැක. දේශීය මූලාකෘති දිගු නොකරන්න.

18
Iny ටයිනිජියන්ට් ඇත්ත වශයෙන්ම: for...inඅරා හරහා නැවත ධාවනය කිරීමට ලූප භාවිතා නොකරන්න .
කොනර් ඕ බ්‍රයන්

66

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

14
නියම පිළිතුර! ස්තූතියි. සෑම තැනකම දෝෂ සහිත කාර්යයන් පිටපත් කර අලවන්නට වඩා පුස්තකාල භාවිතා කිරීමට මිනිසුන් උනන්දු කරන බැවින් මම අනෙක් පිළිතුරු වලට වඩා කැමැත්තෙමි.
frabcus

60
rabrabcus: shuffleශ්‍රිතයක් ලබා ගැනීම සඳහා සම්පූර්ණ පුස්තකාලයක් ඇතුළත් කිරීමෙන් පලක් නැත .
බ්ලෙන්ඩර්

12
මම le බ්ලෙන්ඩර් සමඟ එකඟ නොවෙමි. ඔබට අවශ්‍ය ශ්‍රිතයක් ලබා ගැනීම සඳහා සම්පූර්ණ පුස්තකාලයක් ඇතුළත් කිරීමට බොහෝ හේතු තිබේ. ඒවායින් එකක් නම් ඔබ විසින්ම එය ලියන විට දෝෂයක් ඇතිවීමේ අවදානම අඩුය. නම් එය කාර්ය සාධන ප්රශ්නයක්, එසේ නම් ඔබට එය භාවිතා කළ යුතු නැහැ. නමුත් එය කාර්ය සාධන ගැටලුවක් විය හැකි නිසා එය එසේ වනු ඇතැයි අදහස් නොකෙරේ.
ඩැනියෙල් කැප්ලාන්

7
@tieTYT: ඉතින් ඔබට පුස්තකාලයේ ඉතිරි කොටස අවශ්‍ය වන්නේ ඇයි? ෆිෂර්-යේට්ස් මාරුව ක්‍රියාත්මක කිරීම ඉතා සුළුය. අරාවකින් අහඹු මූලද්‍රව්‍යයක් තෝරා ගැනීමට ඔබට පුස්තකාලයක් අවශ්‍ය නොවේ (එබැවින් මම විශ්වාස කරමි), එබැවින් ඔබ පුස්තකාලයක් භාවිතා කිරීමට කිසිදු හේතුවක් නැත.
බ්ලෙන්ඩර්

18
Le බ්ලෙන්ඩර්: මම එයට හේතුවක් දුන්නා. 1) මම ඔබට සහතික වෙනවා, ඔබ ලියන ඕනෑම කේතයකට දෝෂයක් හඳුන්වා දිය හැකිය, එය කෙතරම් සුළු වුවත්. එය අවදානමට ලක් කරන්නේ ඇයි? 2) පූර්ව ප්‍රශස්තිකරණය නොකරන්න. 3) ඔබට ෂෆල් ඇල්ගෝවක් අවශ්‍ය වන විට 99% ක්ම, ඔබේ යෙදුම වෙනස්වන ඇල්ගෝවක් ලිවීම නොවේ. එය වෙනස්වන ඇල්ගෝවක් අවශ්‍ය දෙයක් ගැන ය . අන් අයගේ වැඩ කටයුතු කරන්න. ඔබට අවශ්‍ය නම් මිස ක්‍රියාත්මක කිරීමේ විස්තර ගැන නොසිතන්න.
ඩැනියෙල් කැප්ලාන්

51

නවතම!

කෙටි හා බොහෝ විට * වේගවත් ෆිෂර්-යේට්ස් මාරු කිරීමේ ඇල්ගොරිතම

  1. එය භාවිතා කරන අතරතුර ---
  2. බිටු සිට බිම දක්වා (දශම සංඛ්‍යා 10 දක්වා සංඛ්‍යා (32bit))
  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 සමඟ ක්‍රියාකාරී නම ලෙස): බයිට් 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
 }
}

6
කාර්ය සාධනය පරීක්ෂා කරන්න ... බොහෝ බ්‍රව්සර්වල 2x වේගවත් ... නමුත් තවත් jsperf පරීක්ෂකයින් අවශ්‍යයි ...
කොකෝ

10
js යනු කෙටිමං සහ එය ලිවීමට විවිධ ක්‍රම පිළිගන්නා භාෂාවකි .. මන්දගාමීව කියවිය හැකි කාර්යයන් බොහොමයක් මෙහි ඇති අතර, එය වඩාත් ක්‍රියාකාරී ආකාරයකින් කළ හැකි ආකාරය පෙන්වීමට මම කැමතියි, එසේම බයිට් කිහිපයක් ඉතිරි කර ගනිමි ... බිට්වේස් සහ කෙටිමං සැබවින්ම මෙහි අවතක්සේරු කර ඇති අතර වෙබය දෝෂ සහිත සහ මන්දගාමී කේත වලින් පිරී ඇත.
කොකෝ

ස්ලෑම් ඩන්ක් පර්ෆ් වැඩි නොවේ. මෙම හුවමාරු fyහා shuffle prototype, මම ලබා fyOS X මෙහෙයුම් පද්ධතිය 10.9.5 (81% මන්දගාමී ~ 100k සාපේක්ෂව ~ 20k මෙහෙයුම්) සහ සෆාරි 7.1 මත Chrome 37 පතුලේ නිරතුරුවම එය ~ 8% මන්දගාමී වෙලා තියෙන්නේ. YMMV, නමුත් එය සැමවිටම වේගවත් නොවේ. jsperf.com/fyshuffle/3
ස්පිග්

සංඛ්‍යාලේඛන නැවත පරීක්ෂා කරන්න ... මම දැනටමත් ලියා ඇත්තේ ක්‍රෝම් මන්දගාමී බවකි. ඔවුන් ගණිතය ප්‍රශස්තිකරණය කර ඇත. අයිඊ, ෆයර්ෆොක්ස් පමණක් නොව ජංගම
උපාංගද පරීක්ෂා කරන්න.

2
මෙය භයානක පිළිතුරකි. SO යනු අපැහැදිලි තරඟයක් නොවේ.
බලු පැටියා

41

අරා මාරු කරන්න

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

ඉතින්, ES6 (ES2015) කොහෙද? [array[i], array[rand]]=[array[rand], array[i]]? සමහර විට ඔබට එය ක්‍රියාත්මක වන ආකාරය ගෙනහැර දැක්විය හැකිය. ඔබ පහළට නැවත යෙදීමට තෝරා ගන්නේ ඇයි?
ෂෙරිෆ්ඩෙරෙක්

@sheriffderek ඔව්, මම භාවිතා කරන ES6 ලක්ෂණය වන්නේ වර්‍ග දෙකක් එකවර පැවරීමයි, එමඟින් එක් කේත පේළියක වර්‍ග දෙකක් මාරු කිරීමට අපට ඉඩ සලසයි.
බෙන් කාප්

නගින ඇල්ගොරිතම යෝජනා කළ ෂෙරිෆ්ඩරෙක්ට ණය. ආරෝහණ ඇල්ගොරිතම ප්‍රේරණයෙන් ඔප්පු කළ හැකිය.
බෙන් කාප්

39

සංස්කරණය කරන්න: මෙම පිළිතුර වැරදිය

අදහස් සහ 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>


හොඳයි, නමුත් සෑම විටම සම්පූර්ණ අහඹු මූලද්‍රව්‍ය ජනනය කරයිද?
ඩීඩීඩී

මම ඔබව නිවැරදිව තේරුම් ගත්තාදැයි විශ්වාස නැත. මෙම ප්‍රවේශය ඇත්ත වශයෙන්ම ඔබ වර්ග කිරීම අරාව ලෙස හඳුන්වන සෑම අවස්ථාවකම අහඹු ලෙස (ව්‍යාජ සසම්භාවී වුවද) අරාව මාරු කරනු ඇත - පැහැදිලි හේතු නිසා එය ස්ථාවර වර්ග කිරීමක් නොවේ.
ක්‍රිස් සෙල්බෙක්

4
Stackoverflow.com/a/18650169/28234 හි විස්තර කර ඇති එකම හේතු නිසා . මෙය අරාවේ ආරම්භය ආසන්නයේ මුල් අංග අතහැර යාමට බොහෝ දුරට ඉඩ ඇත.
ඇලෙක්ස්

7
ඔබට අරාව සීරීමට අවශ්‍ය වූ විට මෙය ඉතා පහසු, පහසු ලයිනර් ය, නමුත් ප්‍රති results ල ශාස්ත්‍රීය වශයෙන් අහඹු ලෙස අහඹු ලෙස තිබීම ගැන ඕනෑවට වඩා නොසිතන්න. සමහර විට, පරිපූර්ණත්වයට අඟල් කිහිපයක් ගතවීම වටිනවාට වඩා වැඩි කාලයක් ගතවේ.
ඩැනියෙල් ග්‍රිස්කොම්

1
මෙය ක්‍රියාත්මක වුවහොත් එය සුන්දර වනු ඇත, නමුත් එය එසේ නොවේ. ඉක්මන් සෙවුම් ක්‍රියා කරන ආකාරය නිසා, නොගැලපෙන සංසන්දකයෙකුට අරාව මූලද්‍රව්‍ය ඒවායේ මුල් ස්ථානයට ආසන්නව තැබීමට ඉඩ ඇත. ඔබේ අරාව සීරීමට ලක් නොවනු ඇත.
සුපර්ලුමිනරි

23

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

4
තොග පිටාර ගැලීමෙන් කේත ඇලවීමට වඩා _.ෂෆල් භාවිතා කිරීමට අපි මිනිසුන් දිරිමත් කළ යුතුය; තවද, මිනිසුන්ගේ තොග පිටාර ගැලීමේ පිළිතුරු සම්පීඩනය කිරීමෙන් අපි අධෛර්යමත් කළ යුතුය. Jsmin යනු එයයි.
ඩේවිඩ් ජෝන්ස්

45
Av ඩේවිඩ් ජෝන්ස්: අරාව මාරු කිරීම සඳහා මම සම්පූර්ණ 4kb පුස්තකාලයක් ඇතුළත් කරන්නේ ඇයි?
බ්ලෙන්ඩර්

1
IngKingKongFrog නම ඇමතීම සාධාරණ ප්‍රජාවක් එක්රැස් කිරීම සඳහා සන්නායක නොවේ.
තිරිඟු

2
var b = පිටත ලූපය ප්‍රකාශ කර එය ලූපයකින් පැවරීම වෙනුවට ලූපයක් තුළ කිරීම කාර්යක්ෂමද b = ?
ඇලෙක්ස් කේ

2
@Brian නෑ වෙනසක්; එසවීම සිදු වන්නේ ප්‍රභව කේතය විග්‍රහ කළ විටය. බොහෝ විට සම්බන්ධ නැත.
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 අහඹු සංඛ්‍යාවක් ධනාත්මක හෝ negative ණ විය හැකි බැවින් වර්ග කිරීමේ ශ්‍රිතය අහඹු ලෙස මූලද්‍රව්‍ය නැවත සකස් කරයි.


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³¹-1 ට වඩා වැඩි විය හැක.
ඔරියෝල්

1
මේ ආකාරයට විනාශ කිරීම එවැනි පිරිසිදු ක්‍රියාවලියක් සඳහා +1
lukejacksonn

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()comparator තේරුම සලකා, lexicographic වේ 10කට වඩා අඩු විය 2සිට 1වඩා අඩු වේ 2.
කාසල්

C 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

Nd ඇන්ඩ්‍රියා කේතය කැඩී ඇත්තේ ෆෝ ලූපය තුළ අරාවෙහි දිග වෙනස් වීම නිසාය. අවසාන සංස්කරණය සමඟ මෙය නිවැරදි වේ.
චාලි වොලස්

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

1
0.5 ණ 0.5 ඇයි? එම අංකයෙන් අදහස් කරන්නේ කුමක්ද?
සාතෙරිස් ස්ටෝම්හැමර්

1
ArtSartherisStormhammer අපි වර්ග කිරීම සඳහා සංසන්දනාත්මක ශ්‍රිතයක් භාවිතා කරන නිසා, එය 0 ට වඩා වැඩි සංඛ්‍යාවක් ලබා දෙන්නේ නම්, සංසන්දනය කරන ලද මූලද්‍රව්‍ය ඇණවුම් කරනු ලබන්නේ දිශාවට පමණි. Math.random () හි -0.5 අපට සෘණ අංකයක් ~ 50% ලබා දෙන අතර එමඟින් අපට ප්‍රතිලෝම අනුපිළිවෙල ලබා දේ.
සෑම් ඩොයිජ්

Straight ජු ඉදිරි හා සරලම විසඳුම. ස්තූතියි
ඩීන්විලියම්මිල්ස්


9

ඔබට මෙය පහසුවෙන් කළ හැකිය:

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

කරුණාකර ජාවාස්ක්‍රිප්ට් වර්ග කිරීමේ අරා වල සඳහන් කරන්න


මෙම ඇල්ගොරිතම දෝෂ සහිත බව බොහෝ කලක සිට ඔප්පු වී ඇත.

කරුණාකර මට ඔප්පු කරන්න. මම පදනම් වූයේ
w3 පාසල්

4
ඔබට ත්‍රෙඩ් එක css-tricks.com/snippets/javascript/shuffle-array හෝ news.ycombinator.com/item?id=2728914 යන වෙබ් අඩවියෙන් කියවිය හැකිය . W3 පාසල් සෑම විටම භයානක තොරතුරු මූලාශ්‍රයක් වී ඇත.

මෙය හොඳ ප්‍රවේශයක් නොවන්නේ මන්ද යන්න පිළිබඳ හොඳ සාකච්ඡාවක් සඳහා 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

ෆිෂර්-යේට්ස් ජාවාස්ක්‍රිප්ට් වල මාරු වීම. මම මෙය මෙහි පළ කරන්නේ උපයෝගීතා ශ්‍රිත දෙකක් (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);
  }
}

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

සංස්කරණය කරන්න : g ග්‍රෙගර්ස් පෙන්වා දුන් පරිදි, සංසන්දනය කිරීමේ ශ්‍රිතය දර්ශකවලට වඩා අගයන් සමඟ හැඳින්වේ, එබැවින් ඔබ භාවිතා කළ indexOfයුතුය. මෙම වෙනස indexOfO (n) කාලය තුළ ධාවනය වන පරිදි විශාල අරා සඳහා කේතය අඩු සුදුසු බව සලකන්න .


Array.prototype.sortදෙකක් වෙයි වටිනාකම් ලෙස aහා bනොවේ, එම දර්ශකය. එබැවින් මෙම කේතය ක්‍රියා නොකරයි.
ග්‍රෙගර්ස්

gers ඔබ නිවැරදියි, මම පිළිතුර සංස්කරණය කළෙමි. ස්තූතියි.
මයිලෝ විලෝන්ඩෙක්

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

මාරුවීමේ තර්කනය : අහඹු දර්ශකයක් තෝරාගෙන ප්‍රති 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ඔවුන් “කැපී පෙනෙන” ලෙස හැඳින්වූ දේ කිරීමට දරුණු ලෙස අකාර්යක්ෂම ක්‍රමයක් විය. ඔබට මුල් අරාව විකෘති කිරීමට අවශ්‍ය නැතිනම්, එය පිටපත් කර වඩාත් කාර්යක්ෂම ඩර්ස්ටන්ෆෙල්ඩ් ප්‍රභේදය භාවිතා කර එම පිටපත මාරු කරන්න.

oratorazaburo, ඔබගේ ප්‍රතිපෝෂණයට ස්තූතියි. සුපිරි
පරිමාණයකට

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

පිළිගත් පිළිතුරට වඩා තදින් එකතු කිරීම මගින් ලබා දෙන වටිනාකම කුමක්ද?
shortstuffsushi

: දැඩි මාදිලිය හා එය ඔබ මෙහි ඒ ගැන කියවන්න පුළුවන් කාර්ය සාධන බලපෑම් ආකාරය ගැන වැඩි විස්තර දැනගැනීම සඳහා developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
රෆායෙල් සී

හ්ම්, ඔබට යොමු කරන ලද ලේඛනයෙන් විශේෂිත යමක් පෙන්වා දිය හැකිද? ජේඑස් එන්ජිමට ප්‍රශස්තිකරණය කිරීම දුෂ්කර විය හැකි බවට ඉහළින් ඇති නොපැහැදිලි අදහස් දැක්වීම හැරුණු විට එහි කිසිවක් “කාර්ය සාධනය වැඩි දියුණු කිරීම” ගැන සඳහන් නොකරයි. මෙම අවස්ථාවේ දී, දැඩි භාවිතය වැඩිදියුණු වන්නේ කුමක් ද යන්න මට පැහැදිලි නැත.
shortstuffsushi

දැඩි මාදිලිය සෑහෙන කාලයක් තිස්සේ පැවතුන අතර, ඕනෑම කෙනෙකුට එය සැමවිටම භාවිතා කළ යුතුද නැද්ද යන්න සහ ඇයිද යන්න පිළිබඳව තමන්ගේ මතය ඉදිරිපත් කිරීමට ප්‍රමාණවත් කියවීම් තිබේ. උදාහරණයක් ලෙස Jslint පැහැදිලි කරන්නේ ඔබ සැමවිටම දැඩි මාදිලිය භාවිතා කළ යුතු බවයි. ඩග්ලස් ක්‍රොක්ෆර්ඩ් විසින් ලිපි ප්‍රමාණයක් සහ හොඳ වීඩියෝ කිහිපයක් ලියා ඇති අතර එය සෑම විටම දැඩි මාදිලිය හොඳ පුහුණුවක් ලෙස භාවිතා කිරීම වැදගත් වන්නේ ඇයිද යන්නත්, V8 වැනි බ්‍රව්සර් ජේඑස් එන්ජින් මගින් එය වෙනස් ලෙස අර්ථකථනය කරන්නේ කෙසේද යන්නත් ය. මම ඔබට එය ගූගල් වෙත තරයේ අවවාද කර ඒ පිළිබඳව ඔබේම මතයක් තබමි.
රෆායෙල් සී

දැඩි මාදිලියේ පරිපූර්ණත්වය පිළිබඳ පැරණි නූලක් මෙන්න, තරමක් පැරණි නමුත් තවමත් අදාළ ය: 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));


5

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; 

-1ඔබ භාවිතා <නොකළ පරිදි n සඳහා a නොතිබිය යුතුය<=
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 ට වඩා අඩුවෙන් අඩංගු අරා සමඟ, කිසිදු නැඹුරුවක් නැති බව ඔබට ආරක්ෂිතව සලකා බැලිය හැකිය.


නිසැකවම අලංකාරයි!
ගර්ෂොම්
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.