如何使用 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,而不是 true
或 false
)
带有while
循环的低效代码,理论上可能导致无限循环
现在,第二个与第三个相结合是这里的主要问题,因为您第一次在数组中测试x
它是undefined
(您只是在if
中使用@987654330 定义它@ 语句,所以 x 最初是未定义的),因此它匹配数组中的第一个元素(即 undefined
,因为您声明 r
和 new 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 )