好的,所以費希爾 - 耶茨洗牌作品的方式是
- 得到一個隨機索引,
r
,從輸入陣列
- 從輸入陣列的輸入陣列到輸出數組
- remove元素
r
拷貝元件r
- 重複
n
次,其中n
是輸入數組的長度
在循環結束時,輸出將是e的混洗副本修改輸入數組。
我打算瀏覽一下小問題:這個算法不應該改變輸入數組。相反,它應該保持輸入數組不變,並返回一個新的數組,它是輸入數組的混洗副本。 (你可以在下面的實現中看到這是如何完成的)。因此,瞭解Fisher-Yates的工作方式,對於您的情況,我們不必洗牌整個陣列,因爲您事先知道您只需要N
元素。
讓我們先看看你的輸入。
var fileContent = this.responseText;
var fileContentLines = fileContent.split('\n');
好,完美。你已經定義了輸入數組,fileContentLines
。現在讓我們來製作一個函數來從中抽取一些隨機元素
// fisher-yates sample
// • sample n elements from xs
// • does not mutate xs
// • guarantees each sampled element is unique
function sample (n,xs) {
function loop(i, output, input, len) {
if (i === n) return output; // loop exit condition
let r = Math.floor(Math.random() * len); // rand number between 0 and len
return loop( // continue loop
i + 1, // increment loop counter
output.concat(input[r]), // copy element r from input
input.slice(0,r).concat(input.slice(r+1)), // remove element from input
len - 1 // decrement length
);
}
return loop(0, [], xs, xs.length); // begin loop
}
好吧!我們首先用一個簡單的輸入檢查它
// sample 3 random inputs from numbers 1 through 10
console.log(sample(3, [1,2,3,4,5,6,7,8,9,10])); //=> [9,7,5]
完美。現在只是把它的線
var result = sample(5, fileContentLines);
console.log(result); // ...
上面的代碼工作的陣列上,但我們不要停在這裏。我們的代碼承擔了太多的責任,我們可以將一些行爲分解爲可重用的函數。
// get rand number between 0 and n
function rand(x) {
return Math.floor(Math.random() * x);
}
// splice of xs at index i
// • return a new output array
// • does not mutate xs
function del(i,xs) {
return xs.slice(0,i).concat(xs.slice(i+1));
}
// fisher-yates sample
// • sample n elements from xs
// • does not mutate xs
// • guarantees each sampled element is unique
function sample (n,xs) {
function loop(i, output, input, len) {
if (i === n) return output; // loop exit condition
let r = rand(len); // rand number between 0 and len
return loop( // continue loop
i + 1, // increment loop counter
output.concat(input[r]), // copy element r from input
del(r,input), // remove element from input
len - 1 // decrement length
);
}
return loop(0, [], xs, xs.length); // begin loop
}
// fisher-yates shuffle
// • does not mutate xs
function shuffle(xs) {
return sample(xs.length, xs);
}
讓我們快速瀏覽一下各功能
// generate random number between 0 and 10 (exclusive)
console.log(rand(10)); //=> 5
// delete 2nd letter from letters a through d
console.log(del(1, ['a', 'b', 'c', 'd'])); // => ['a', 'c', 'd]
// sample 3 random inputs from numbers 1 through 10
console.log(sample(3, [1,2,3,4,5,6,7,8,9,10])); //=> [9,7,5]
// shuffle entire input array
console.log(shuffle([1,2,3,4,5,6,7,8,9,10])); //=> [8,9,1,3,7,6,10,5,4,2]
還有的個體行爲,你就會明白:對於1價格4種功能。在我看來,這是一個更好的解決問題的方法,因爲每個函數都是有用的,因此可以在多個地方使用。擁有許多小的可重用功能將大大減少您將來必須完成的工作量。
由於所有這些複雜性都很好地劃分了,我們來看看你的最終代碼是什麼樣的。
function createParagraph(text) {
var p = document.createElement('p');
p.innerHTML = text;
return p;
}
var request = new XMLHttpRequest();
request.onload = function() {
var fileContent = this.responseText;
var fileContentLines = fileContent.split('\n');
var target = document.getElementById('random-testimonial');
sample(5, fileContentLines).map(function(testimonial) {
var p = createParagraph(testimonial);
target.appendChild(p);
});
};
request.open('GET', 'content.txt', true);
request.send();
PS我強烈建議你寫的可重複使用的功能,爲您的Ajax請求,或更好,使用圖書館。用手書寫它們非常麻煩並且容易出錯。大多數人使用jQuery,但最近我一直在尋找axios
嘗試用'.indexOf()'替換'.contains()'if'condition – guest271314