简体   繁体   English

Txt文件中的Javascript Shuffle数组

[英]Javascript Shuffle Array from Txt File

I am looking to pull 5 "random" lines from a text file while not repeating any. 我希望从文本文件中提取5条“随机”行,而不重复任何行。 Each line from the text file has html code which would be inserted into a side menu. 文本文件中的每一行都有html代码,这些代码将插入到侧面菜单中。 I have read up on the Fisher–Yates shuffle but not sure how to incorporate it in this manner with javascript. 我已经阅读了Fisher-Yates随机播放的内容,但不确定如何将这种方式与javascript合并。 Presently I have the following throwing an error: 目前,我有以下引发错误的内容:

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

and

<div id="random-content"><script src="content.js"></script></div>

Error: 错误:

content.js:19 Uncaught TypeError: targetHTML.contains is not a functionrequest.onload @ content.js:19 content.js:19未捕获的TypeError:targetHTML.contains不是functionrequest.onload @ content.js:19

OK, so the way Fisher-Yates shuffle works is 好的,所以Fisher-Yates洗牌的工作方式是

  • get a random index, r , from the input array 从输入数组获取随机索引r
  • copy element r from the input array to the output array 将元素r从输入数组复制到输出数组
  • remove element r from the input array 从输入数组中删除元素r
  • repeat n times, where n is the length of the input array 重复n次,其中n是输入数组的长度

By the end of the loop, the output will be a shuffled copy of the entire input array. 到循环结束时,输出将是整个输入数组的改组副本。

I'm going to glance over one small gotcha: this algorithm shouldn't mutate the input array. 我将看一下一个小陷阱:该算法不应使输入数组发生变异。 Instead it should leave the input array untouched and return a new array that is a shuffled copy of the input array. 相反,它应该保持输入数组不变,并返回一个新数组,该数组是输入数组的随机组合副本。 (You can see how this is done in my implementation below). (您可以在下面的实现中看到如何完成此操作)。

So knowing how Fisher-Yates works, in your case, we don't have to shuffle the entire array since you know before-hand that you only want N elements. 因此,在您的情况下,了解Fisher-Yates的工作原理,我们就不必重新整理整个数组,因为您事先知道只需要N元素。

Let's first look at your input. 我们首先来看一下您的输入。

var fileContent = this.responseText;
var fileContentLines = fileContent.split( '\n' );

OK, perfect. 好,完美。 You've defined the input array, fileContentLines . 您已经定义了输入数组fileContentLines Now let's make a function to sample some random elements from it 现在让我们做一个函数来从中抽取一些随机元素

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

Alright ! 好的 ! Let's first check it with a simple input 我们先用一个简单的输入检查一下

// 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]

Perfect. 完善。 Now just call it on your array of lines 现在只需在您的行数组上调用它

var result = sample(5, fileContentLines);
console.log(result); // ...

The above code works, but let's not stop here. 上面的代码有效,但我们不要就此停止。 Our code is taking on too much responsibility and we can separate some of the behaviours into reusable functions. 我们的代码承担了太多的责任,我们可以将某些行为分成可重用的功能。

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

Let's take a quick look at the individual behaviour of each function 让我们快速看一下每个函数的个别行为

// 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]

And there you have it: 4 functions for the price of 1 . 在那里,您可以找到: 4个功能,价格为1 In my opinion, this is a much better way to solve the problem because each function is useful on its own and therefore can be used in multiple places. 我认为,这是解决问题的一种更好的方法,因为每个函数本身都是有用的,因此可以在多个地方使用。 Having lots of little reusable functions will drastically reduce the amount of work you'll have to do in the future. 具有许多小的可重用功能,将大大减少您将来要做的工作量。


With all of this complexity nicely compartmentalized, let's see what your final code might look like. 很好地划分了所有这些复杂性,让我们看看您的最终代码是什么样子。

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 I highly recommend you write reusable functions for your ajax requests, or better, use a library. PS我强烈建议您为ajax请求编写可重用的函数,或者最好使用库。 Writing them by hand is extremely cumbersome and error prone. 手工编写它们非常麻烦且容易出错。 Most people use jQuery but lately I've been reaching for axios 大多数人使用jQuery,但是最近我一直在接触axios

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM