如何使用 jQuery.inArray 方法选择一组唯一的随机数(不重复)?

Posted

技术标签:

【中文标题】如何使用 jQuery.inArray 方法选择一组唯一的随机数(不重复)?【英文标题】:How to choose a set of unique random numbers (no duplicates) using the jQuery.inArray method? 【发布时间】:2011-07-05 19:55:53 【问题描述】:

这是一个 javascript / jQuery 问题:

我正在尝试使用 jQuery.inArray 方法生成 1 到 21 之间的六个唯一随机数(不重复)。然后,这六个数字将用于从名为 logo1.jpg 到 logo21.jpg 的组中选择六个 .jpg 文件。

谁能告诉我我在这里做错了什么?

<div id="client-logos"></div>

<script src="http://code.jquery.com/jquery-1.5.js"></script>

<script type="text/javascript">

Show = 6; // Number of logos to show
TotalLogos = 21; // Total number of logos to choose from
FirstPart = '<img src="/wp-content/client-logos/logo';
LastPart = '.jpg"   />';
r = new Array(Show); // Random number array

var t=0;
for (t=0;t<Show;t++)
   
      while ( jQuery.inArray(x,r)
         
            var x = Math.ceil(Math.random() * TotalLogos);
         );
      r[t] = x;
      var content = document.getElementById('client-logos').innerhtml;
      document.getElementById('client-logos').innerHTML = content + FirstPart + r[t] + LastPart;
   

</script>

提前谢谢...

【问题讨论】:

你确定这是对的吗?在我看来,围绕“while”循环的语法错误 - 缺少近括号 ... 另外,看起来你用每个随机图像一遍又一遍地更新完全相同的元素。这真的是你想要的吗? @Pointy:他在重新分配之前将 innerHTML 设置为 content 变量。 @Shaun:顺便说一句,在循环内修改 innerHTML 通常是不好的做法。在循环中生成 HTML 字符串,但在循环结束之前不要将其分配给元素。 @Andy E 哦,我明白了 - 好吧,这会起作用,但由于其他原因,这是一个坏主意,正如你所指出的 :-) @Shaun 更好的方法是使用 Fisher-Yates(或 Knuth)洗牌 - 关于这个主题的 a Wikipedia article 非常容易理解。您将构建一个由 1 到 21 组成的数组,将其随机排列,然后从列表中选择前 6 个。 【参考方案1】:

你有几个问题:

全局窗口范围内的变量

使用 new 关键字而不是文字声明的数组

在声明变量之前尝试使用变量

jQuery.inArray 使用不正确(inArray returns a number,而不是 truefalse

带有while 循环的低效代码,理论上可能导致无限循环

现在,第二个与第三个相结合是这里的主要问题,因为您第一次在数组中测试x 它是undefined(您只是在if 中使用@987654330 定义它@ 语句,所以 x 最初是未定义的),因此它匹配数组中的第一个元素(即 undefined,因为您声明 rnew Array(6))并且 inArray 函数返回 1,这导致无限循环。

您可以做几件事来修补该代码,但我认为用不同的方法完全重写可能会更好,并且根本不需要 jQuery。

您的代码的这个修改版本应该可以正常工作:

var Show = 6, // Number of logos to show
    TotalLogos = 21, // Total number of logos to choose from
    FirstPart = '<img src="/wp-content/client-logos/logo',
    LastPart = '.jpg"   />',
    array = [], // array with all avaiilable numbers
    rnd, value, i,
    logosElement = document.getElementById('client-logos');

for (i = 0; i < TotalLogos; i++)  // arrays are zero based, for 21 elements you want to go from index 0 to 20.
  array[i] = i + 1;


for (i = 0; i < Show; i++)  // pick numbers
  rnd = Math.floor(Math.random() * array.length); 
  value = array.splice(rnd,1)[0]; // remove the selected number from the array and get it in another variable

  logosElement.innerHTML += (FirstPart + value + LastPart);

解释一下我在这里做了什么:

使用您拥有的所有可能值(数字 1 到 21)初始化一个数组

循环运行次数与您想选择的数字一样多。

从 0 到您的 numbers 数组中可用的最大索引生成一个随机数

使用拼接从数组中删除该索引处的数字,然后使用它为 innerHTML 调用创建字符串 (splice returns the elements removed from the array as another new array)。

此外,logosElement 变量在开头被缓存,因此您只需对元素进行一次 DOM 查找。

有更多方法可以重写甚至清理代码,但我认为这是帮助您解决问题的最简洁的方法(而且它是跨浏览器安全的!除非您需要它,否则无需添加 jQuery另一个功能)

【讨论】:

哇!效果很好,你解释得非常好。谢谢你一千次。【参考方案2】:

除了while 循环后的额外右括号外,它不起作用的最明显原因是对$.inArray 方法的工作原理略有误解。 $.inArray 返回数组中匹配值的第一个索引,如果未找到,则返回 -1-1 是一个“真实”值,这意味着如果随机数不在数组中,你的 while 循环将继续执行。实际上,它会继续执行,直到找到数组第 0 位的数字为止。

为了解决该特定问题,您需要检查它是否大于 -1,并在循环之前将 x var 设置为随机数:

var x = Math.ceil(Math.random() * TotalLogos);

while ($.inArray(x, r) > -1) 
    x = Math.ceil(Math.random() * TotalLogos);

r[t] = x;

在对您问题的评论回复中,Pointy 还提到了 Fisher-Yates Shuffle。与您使用的方法相比,这种改组方法可能会为您提供更好的分布。

【讨论】:

这可能是一个无限循环【参考方案3】:
// Initial number
var x = Math.ceil(Math.random() * TotalLogos);

// Keep searching until a unique number is found
while ($.inArray(x, r) > -1) 
    x = Math.ceil(Math.random() * TotalLogos);


// If it's unique, set it
r[t] = x;

【讨论】:

谢谢埃德!我最终选择了@gonchuki 的解决方案,但感谢您的回复。 这可能是一个无限循环

以上是关于如何使用 jQuery.inArray 方法选择一组唯一的随机数(不重复)?的主要内容,如果未能解决你的问题,请参考以下文章

jQuery.inArray( value, array )

使用jQuery $ .inArray

js如何实现php的in_array()

几个有用的JavaScript/jQuery代码片段(转)

使用 jquery inarray() 搜索字符串变量返回 -1

$.inArray()