Javascript 从 Txt 文件随机排列数组
Javascript Shuffle Array from Txt File
我希望从文本文件中提取 5 "random" 行而不重复任何行。文本文件中的每一行都有 html 代码,这些代码将被插入到侧边菜单中。我已经阅读了 Fisher–Yates shuffle,但不确定如何以这种方式将其与 javascript 合并。目前我有以下抛出错误:
var request = new XMLHttpRequest();
request.onload = function() {
var i = 0;
// get the file contents
var fileContent = this.responseText;
// split into lines
var fileContentLines = fileContent.split( '\n' );
var target = document.getElementById( 'random-testimonial' );
var targetHTML = target.innerHTML;
while ( i < 5 ) {
// get a random index (line number)
var randomLineIndex = Math.floor( Math.random() * fileContentLines.length );
// extract the value
var randomLine = fileContentLines[ randomLineIndex ];
// add the random line in a div if not duplicate
if ( ! targetHTML.contains(randomLine) ) {
targetHTML += randomLine;
i += 1;
}
}
target.innerHTML = targetHTML;
};
request.open( 'GET', 'content.txt', true );
request.send();
和
<div id="random-content"><script src="content.js"></script></div>
错误:
content.js:19 未捕获类型错误:targetHTML.contains 不是 functionrequest.onload @ content.js:19
var request = new XMLHttpRequest();
request.onload = function() {
var i = 0;
// get the file contents
var fileContent = this.responseText;
// split into lines
var fileContentLines = fileContent.split( '\n' );
var target = document.getElementById( 'random-testimonial' );
var HTMLLines = [];
while ( i < 5 ) {
// get a random index (line number)
var randomLineIndex = Math.floor( Math.random() * fileContentLines.length );
// extract the value
var randomLine = fileContentLines[ randomLineIndex ];
// add the random line if not duplicate
if ( HTMLLines.indexOf(randomLine) === -1) {
HTMLLines.push(randomLine);
i += 1;
}
}
target.innerHTML = HTMLLines.join('\n');
};
request.open( 'GET', 'content.txt', true );
request.send();
好的,Fisher-Yates 洗牌的工作方式是
- 从输入数组
中获取随机索引r
- 从输入数组复制元素
r
到输出数组
- 从输入数组中删除元素
r
- 重复
n
次,其中n
是输入数组的长度
到循环结束时,输出将是整个输入数组的随机副本。
我将浏览一个小陷阱:该算法不应改变输入数组。相反,它应该保持输入数组不变,并 return 一个新数组,它是输入数组的随机副本。 (您可以在下面的我的实现中看到这是如何完成的)。
所以知道 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]
你有它:4 个功能,价格为 1。在我看来,这是一种更好的解决问题的方法,因为每个函数都可以单独使用,因此可以在多个地方使用。拥有大量可重用的小功能将大大减少您将来必须做的工作量。
所有这些复杂性都很好地划分了,让我们看看您的最终代码可能是什么样子。
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 but lately I've been reaching for axios
我希望从文本文件中提取 5 "random" 行而不重复任何行。文本文件中的每一行都有 html 代码,这些代码将被插入到侧边菜单中。我已经阅读了 Fisher–Yates shuffle,但不确定如何以这种方式将其与 javascript 合并。目前我有以下抛出错误:
var request = new XMLHttpRequest();
request.onload = function() {
var i = 0;
// get the file contents
var fileContent = this.responseText;
// split into lines
var fileContentLines = fileContent.split( '\n' );
var target = document.getElementById( 'random-testimonial' );
var targetHTML = target.innerHTML;
while ( i < 5 ) {
// get a random index (line number)
var randomLineIndex = Math.floor( Math.random() * fileContentLines.length );
// extract the value
var randomLine = fileContentLines[ randomLineIndex ];
// add the random line in a div if not duplicate
if ( ! targetHTML.contains(randomLine) ) {
targetHTML += randomLine;
i += 1;
}
}
target.innerHTML = targetHTML;
};
request.open( 'GET', 'content.txt', true );
request.send();
和
<div id="random-content"><script src="content.js"></script></div>
错误:
content.js:19 未捕获类型错误:targetHTML.contains 不是 functionrequest.onload @ content.js:19
var request = new XMLHttpRequest();
request.onload = function() {
var i = 0;
// get the file contents
var fileContent = this.responseText;
// split into lines
var fileContentLines = fileContent.split( '\n' );
var target = document.getElementById( 'random-testimonial' );
var HTMLLines = [];
while ( i < 5 ) {
// get a random index (line number)
var randomLineIndex = Math.floor( Math.random() * fileContentLines.length );
// extract the value
var randomLine = fileContentLines[ randomLineIndex ];
// add the random line if not duplicate
if ( HTMLLines.indexOf(randomLine) === -1) {
HTMLLines.push(randomLine);
i += 1;
}
}
target.innerHTML = HTMLLines.join('\n');
};
request.open( 'GET', 'content.txt', true );
request.send();
好的,Fisher-Yates 洗牌的工作方式是
- 从输入数组 中获取随机索引
- 从输入数组复制元素
r
到输出数组 - 从输入数组中删除元素
r
- 重复
n
次,其中n
是输入数组的长度
r
到循环结束时,输出将是整个输入数组的随机副本。
我将浏览一个小陷阱:该算法不应改变输入数组。相反,它应该保持输入数组不变,并 return 一个新数组,它是输入数组的随机副本。 (您可以在下面的我的实现中看到这是如何完成的)。
所以知道 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]
你有它:4 个功能,价格为 1。在我看来,这是一种更好的解决问题的方法,因为每个函数都可以单独使用,因此可以在多个地方使用。拥有大量可重用的小功能将大大减少您将来必须做的工作量。
所有这些复杂性都很好地划分了,让我们看看您的最终代码可能是什么样子。
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 but lately I've been reaching for axios