【问题标题】:Random array selection without selecting twice in JavaScript随机数组选择而不在 JavaScript 中选择两次
【发布时间】:2011-08-20 17:16:02
【问题描述】:

所以,我试图从一个数组中随机选择一个条目,然后让它在每个条目都被选中之前不会再次被选中。 基本上,在选择数组中的所有条目之前,我不想看到任何相同的条目。

如果这是我的数组……

keywords =
[
 "ppc",
 "games",
 "advertise",
 "meta",
 "home",
 "gaming",
 "welcome"
]
var keyword = keywords[Math.floor(Math.random()*keywords.length)]
document.write(keyword);

我不想看到以下输出:

meta, advertise, home, meta, gaming, welcome, ppc, welcome

因为在选择所有内容之前第二次选择了元数据。 我希望看到更多类似的东西:

meta, advertise, gaming,ppc, welcome, home, games, advertise, ppc,

因为在随机选择每个条目之前,它没有多次选择任何条目。(第二个循环从第二个“广告”开始,以防您没有发现差异。

但正如您从我上面发布的代码中看到的那样,我不知道该怎么做。我已经看到了随机选择的条目实际上完全从数组中删除的示例,但这不是我想要做的。我只想选择每个条目一次,然后重新启动该过程。

有人知道这个代码吗?

【问题讨论】:

标签: javascript arrays random


【解决方案1】:

如果您不介意更改数组,您可以随机化数组中元素的顺序,然后从第一个元素到最后一个元素打印数组。

您可以创建另一个值从 1 到 N 的数组(其中 n 是元素的数量)。随机化该数组的顺序,然后在从第一个到最后一个迭代它时将其用作数组的索引。

【讨论】:

    【解决方案2】:

    您可以使用 Array.sort() 函数对其进行随机排序。

    // random sort function
    function shuffle(a, b)
    {
       return Math.random() > 0.5 ? -1 : 1;
    }
    
    var keywords = ["ppc", "games", "advertise", "meta", "home", "gaming", "welcome"];
    
    var randomKeywords = keywords.sort(shuffle); // new instance of a sorted randomly copy of the array
    
    alert(randomKeywords);
    

    更新:

    更好的洗牌解决方案是使用 Fisher-Yates Shuffle,如 answer 中所述。

    function shuffle(array)
    {
      var m = array.length, t, i;
      while (m > 0) 
      {
    	i = Math.floor(Math.random() * m--);
    	t = array[m];
    	array[m] = array[i];
    	array[i] = t;
      }
      return array;
    }
    
    var keywords = ["ppc", "games", "advertise", "meta", "home", "gaming", "welcome"];
    
    shuffle(keywords); // shuffles the array
    
    alert(keywords);

    【讨论】:

    • 这不适用于 Linux 上的 Firefox 和 Opera。我需要删除shuffle() 中的-1。如果 sort 如何处理来自排序函数的0 取决于实现,那么shuffle() 的主体中的return (Math.random() > 0.5) ? -1 : 1; 怎么样?
    【解决方案3】:

    一个非常简单的方法是每次选择一个随机元素时使用splice,一旦数组为空,就用原始值重新填充它。

    例子:

    (function () {
        var arr = [];
    
        window.getRandomThing = function () {
            if (arr.length === 0) {
                refill();
            }
    
            return arr.splice(Math.random() * arr.length, 1)[0];
        };
    
        function refill () {
            arr = [1,2,3,4,5];
        }
    } ());
    

    【讨论】:

      【解决方案4】:

      您可以制作原始数组的副本,然后使用.splice() 在随机索引处获取一个值,并将其从副本数组中删除

      因为副本是每次减一,所以你可以简单地做while( copy.length )

      示例: http://jsfiddle.net/fMXTF/

      var keywords = [
       "ppc",
       "games",
       "advertise",
       "meta",
       "home",
       "gaming",
       "welcome"
      ];
      
      var copy = keywords.slice();
      
      while( copy.length ) {
      
          var keyword = copy.splice( Math.floor(Math.random()*copy.length), 1 );
          document.write(keyword + '<br>');
      
      }
      

      请注意,随机数基于copy.length,由于.splice(),在每次迭代中都会减少1。因此它确保随机数始终基于副本的当前length

      【讨论】:

        【解决方案5】:

        将您看到的数字(索引)存储在哈希中,然后当您尝试查看一个新单词时,您可以检查哈希,如果您已经看过它,则生成一个新数字。确保检查哈希长度是否与数组长度相同。

        这样可以避免改变数组。

        【讨论】:

        • 但是假设您有一个包含 1000 个索引的数组,找到唯一索引的概率会随着每次迭代呈指数增长。对于最后的选择,您将有 1000 分之一的机会结束该功能。所以循环会额外迭代 1000 次,甚至更多。当您添加索引时,这也成为一个更大的问题。您的拣货功能可能需要几分钟才能结束。
        • 最好的解决方案是选择一个随机索引,然后将该索引与您选择的那个交换到数组的末尾,然后使用 (array.Length - 1 - i) 再次循环保证了 O/n 的最优选择。
        【解决方案6】:

        user113716盗来的,但做了一点优化。

        var arr = [
            "ppc",
            "games",
            "advertise",
            "meta",
            "home",
            "gaming",
            "welcome"];
        
        Array.prototype.shuffle = Array.prototype.shuffle || function () {
            var copy = this.slice(), arr = [];
            while (copy.length) arr.push(copy.splice((Math.random() * copy.length) << 0));
            return arr;
        };
        
        alert(arr.shuffle());
        

        【讨论】:

          猜你喜欢
          • 2013-10-28
          • 2012-10-22
          • 2016-02-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-27
          • 2019-01-28
          相关资源
          最近更新 更多