Bir JavaScript dizisi nasıl rastgele hale getirilir (karıştırılır)?

Şöyle bir dizim var:

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

Bunu nasıl rastgele hale getirebilir / karıştırabilirim?

Çözüm

Fiili tarafsız karıştırma algoritması Fisher-Yates (Knuth olarak da bilinir) Shuffle'dır.

Bkz. https://github.com/coolaj86/knuth-shuffle

Burada harika bir görselleştirme (ve bununla bağlantılı orijinal gönderiyi) görebilirsiniz

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];
arr = shuffle(arr);
console.log(arr);

Kullanılan algoritma hakkında biraz daha bilgi.

Yorumlar (27)

Fisher-Yates'in bilgisayar için optimize edilmiş bir versiyonu olan [Durstenfeld shuffle]'ın (http://en.wikipedia.org/wiki/Fisher-Yates_shuffle#The_modern_algorithm) JavaScript uygulaması:

/**
 * Randomize array element order 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;
    }
}

Fisher-Yates algoritması, her orijinal dizi elemanı için bir rastgele eleman seçerek ve ardından bir sonraki çekilişten hariç tutarak çalışır. Tıpkı bir deste karttan rastgele seçim yapmak gibi.

Bu dışlama akıllıca bir yolla (Durstenfeld tarafından bilgisayarlar tarafından kullanılmak üzere icat edilmiştir), seçilen elemanı mevcut elemanla değiştirerek ve ardından kalandan bir sonraki rastgele elemanı seçerek yapılır. Optimum verimlilik için, döngü geriye doğru çalışır, böylece rastgele seçim basitleştirilir (her zaman 0'dan başlayabilir) ve artık başka seçenek olmadığı için son öğeyi atlar.

Bu algoritmanın çalışma süresi O(n)'dir. Karıştırma işleminin yerinde yapıldığına dikkat edin. Bu nedenle, orijinal diziyi değiştirmek istemiyorsanız, önce .slice(0) ile bir kopyasını oluşturun.

ES6 / ECMAScript 2015'e Güncelleme

Yeni ES6 aynı anda iki değişken atamamıza izin veriyor. Bu, özellikle iki değişkenin değerlerini değiştirmek istediğimizde kullanışlıdır, çünkü bunu tek bir kod satırında yapabiliriz. İşte aynı fonksiyonun bu özelliği kullanan daha kısa bir biçimi.

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

Biri bunu Array'den bir protoype olarak kullanabilir (veya kullanmalıdır):

ChristopheD'den:

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