生成 1 到 100 之间的唯一随机数
如何使用 JavaScript 生成 1 到 100 之间的一些唯一随机数字?
How can I generate some unique random numbers between 1 and 100 using JavaScript?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
将其实现为生成器使其使用起来非常愉快。请注意,此实现与需要首先对整个输入数组进行混洗的实现不同。
我选择以不改变输入数组的方式实现示例,但您可以很容易地认为改变实现是有利的。
例如,
shuffle
函数可能希望改变原始输入数组。或者您可能希望在不同时间从相同的输入中进行采样,每次都更新输入。由于数组输入突变,
sample
不再是一个纯函数,但在某些情况下(如上所示)它可能更有意义。我选择生成器而不是仅返回数组的函数的另一个原因是,您可能希望继续采样,直到出现某些特定条件。
也许我想要 1,000,000 个随机数列表中的第一个素数。
因为我们使用的是生成器,所以这个任务很简单。
它将一次连续采样 1 个随机数
x
,检查它是否为素数,如果是则返回x
是。如果在找到素数之前耗尽数字列表,则返回 NaN。注意:
此答案最初是在另一个问题上共享的,该问题作为与此问题的重复项而被关闭。因为它与此处提供的其他解决方案非常不同,所以我决定也在这里分享
Implementing this as a generator makes it pretty nice to work with. Note, this implementation differs from ones that require the entire input array to be shuffled first.
I chose to implement
sample
in a way that does not mutate the input array, but you could easily argue that a mutating implementation is favourable.For example, the
shuffle
function might wish to mutate the original input array. Or you might wish to sample from the same input at various times, updating the input each time.sample
is no longer a pure function because of the array input mutation, but in certain circumstances (demonstrated above) it might make more sense.Another reason I chose a generator instead of a function that just returns an array is because you may want to continue sampling until some specific condition.
Perhaps I want the first prime number from a list of 1,000,000 random numbers.
Because we're working with a generator, this task is trivial
This will continuously sample 1 random number at a time,
x
, check if it's prime, then returnx
if it is. If the list of numbers is exhausted before a prime is found,NaN
is returned.Note:
This answer was originally shared on another question that was closed as a duplicate of this one. Because it's very different from the other solutions provided here, I've decided to share it here as well
与 The Machine Charmer 相同的排列算法,但具有原型实现。更适合大量选择。使用 js 1.7 解构赋值(如果可用)。
编辑:
另一个建议,更适合少量的选择,基于 belugabob 的答案。为了保证唯一性,我们从数组中删除选取的数字。
Same permutation algorithm as The Machine Charmer, but with a prototyped implementation. Better suited to large number of picks. Uses js 1.7 destructuring assignment if available.
Edit:
An other proposition, better suited to small number of picks, based on belugabob's answer. To guarantee uniqueness, we remove the picked numbers from the array.
对于像这样有孔的数组
[,2,,4,,6,7,,]
因为我的问题是填补这些漏洞。所以我根据我的需要修改了它:)
以下修改后的解决方案对我有用:)
for arrays with holes like this
[,2,,4,,6,7,,]
because my problem was to fill these holes. So I modified it as per my need :)
the following modified solution worked for me :)
早期最好的答案是
sje397
的答案。您将尽快获得尽可能好的随机数。我的解决方案与他的解决方案非常相似。然而,有时您想要随机顺序的随机数,这就是我决定发布答案的原因。另外,我提供了一个通用的功能。
The best earlier answer is the answer by
sje397
. You will get as good random numbers as you can get, as quick as possible.My solution is very similar to his solution. However, sometimes you want the random numbers in random order, and that is why I decided to post an answer. In addition, I provide a general function.
这是我拼凑而成的 ES6 版本。我确信它可以更加巩固一些。
Here is my ES6 version I cobbled together. I'm sure it can be a little more consolidated.
这就是我在 ES6 中的做法,并且不使用
while
。这也永远不会返回 0。如果其中有用户输入,您可能还需要进行一些错误处理。
This is how I'd do it in ES6 and without using
while
. This will never return a 0 either.You may also want to do some error handling if there is going to be user input in this.
如何使用对象属性作为哈希表?这样你最好的情况就是只随机化 8 次。仅当您想要数字范围的一小部分时,它才有效。它比 Fisher-Yates 占用的内存要少得多,因为您不必为数组分配空间。
然后我发现 Object.keys(obj) 是ECMAScript 5 功能,因此上述内容现在在互联网上几乎没有用处。不用担心,因为我通过添加这样的键函数使其与 ECMAScript 3 兼容。
How about using object properties as a hash table? This way your best scenario is to only randomize 8 times. It would only be effective if you want a small part of the range of numbers. It's also much less memory intensive than Fisher-Yates because you don't have to allocate space for an array.
I then found out that Object.keys(obj) is an ECMAScript 5 feature so the above is pretty much useless on the internets right now. Fear not, because I made it ECMAScript 3 compatible by adding a keys function like this.
如果您需要更多唯一性,则必须生成一个数组(1..100)。
上面的代码更快:
extractUniqueRandomArray(50)=>;
[2, 79, 38, 59, 63, 42, 52, 22, 78, 50, 39, 77, 1, 88, 40, 23, 48, 84, 91, 49, 4, 54, 93, 36, 100 , 82, 62, 41, 89, 12, 24, 31, 86, 92, 64, 75, 70, 61, 67, 98, 76, 80, 56, 90, 83, 44, 43, 47, 7, 53 ]
if you need more unique you must generate a array(1..100).
above code is faster:
extractUniqueRandomArray(50)=>
[2, 79, 38, 59, 63, 42, 52, 22, 78, 50, 39, 77, 1, 88, 40, 23, 48, 84, 91, 49, 4, 54, 93, 36, 100, 82, 62, 41, 89, 12, 24, 31, 86, 92, 64, 75, 70, 61, 67, 98, 76, 80, 56, 90, 83, 44, 43, 47, 7, 53]
使用 JavaScript 1.6 indexOf 函数添加相同代码的另一个更好版本(已接受的答案)。每次检查重复项时不需要循环遍历整个数组。
旧版本的 Javascript 仍然可以使用顶部的版本
PS:尝试建议更新 wiki 但被拒绝。我仍然认为它对其他人可能有用。
Adding another better version of same code (accepted answer) with JavaScript 1.6 indexOf function. Do not need to loop thru whole array every time you are checking the duplicate.
Older version of Javascript can still use the version at top
PS: Tried suggesting an update to the wiki but it was rejected. I still think it may be useful for others.
这是我个人的解决方案:
它随机生成 8 个唯一的数组值(0 到 7 之间),然后使用警报框显示它们。
This is my personal solution :
It randomly generates 8 unique array values (between 0 and 7), then displays them using an alert box.
我认为这个方法与大多数答案中给出的方法不同,所以我想我可以在这里添加一个答案(尽管这个问题是4年前提出的)。
我们生成 100 个随机数,并用 1 到 100 之间的数字标记每个随机数。然后我们对这些标记的随机数进行排序,并且标记被随机打乱。或者,根据本问题的需要,可以不再只查找标记随机数的前 8 个。查找前 8 个项目比对整个数组进行排序要便宜。
这里必须注意的是,排序算法会影响该算法。如果所使用的排序算法稳定,则存在轻微偏向于较小数字的情况。理想情况下,我们希望排序算法不稳定,甚至不偏向稳定(或不稳定),以产生具有完全均匀概率分布的答案。
I think this method is different from methods given in most of the answers, so I thought I might add an answer here (though the question was asked 4 years ago).
We generate 100 random numbers, and tag each of them with numbers from 1 to 100. Then we sort these tagged random numbers, and the tags get shuffled randomly. Alternatively, as needed in this question, one could do away with just finding top 8 of the tagged random numbers. Finding top 8 items is cheaper than sorting the whole array.
One must note here, that the sorting algorithm influences this algorithm. If the sorting algorithm used is stable, there is slight bias in favor of smaller numbers. Ideally, we would want the sorting algorithm to be unstable and not even biased towards stability (or instability) to produce an answer with perfectly uniform probability distribution.
这可以处理生成最多 20 位唯一随机数
JS
jsFiddle
This can handle generating upto 20 digit UNIQUE random number
JS
jsFiddle
该解决方案使用哈希,其性能比检查是否驻留在数组中的 O(1) 性能高得多。它还具有额外的安全检查。希望有帮助。
This solution uses the hash which is much more performant O(1) than checking if the resides in the array. It has extra safe checks too. Hope it helps.
您也可以使用这样的单行代码来完成此操作:
[...((add, set) => add(set, add))((set, add) => set.size < 8添加(set.add(Math.floor(Math.random()*100) + 1), add) : set, new Set())]
You can also do it with a one liner like this:
[...((add, set) => add(set, add))((set, add) => set.size < 8 ? add(set.add(Math.floor(Math.random()*100) + 1), add) : set, new Set())]
使用
Set
是最快的选择。这是一个使用回调生成器获取唯一随机数的通用函数。现在它快速并且可重复使用。Using a
Set
is your fastest option. Here is a generic function for getting a unique random that uses a callback generator. Now it's fast and reusable.这是 Fisher Yates/Durstenfeld Shuffle 的实现,但没有实际创建当拾取大小与可用元素数量相比较小时,可以使用数组,从而降低空间复杂度或所需的内存。
要从 100 个数字中选取 8 个数字,无需创建包含 100 个元素的数组。
假设创建了一个数组,
rnd
)rnd
如果未创建数组,则可以使用 hashMap 来记住实际交换的位置。当生成的第二个随机数等于先前生成的随机数之一时,地图提供该位置的当前值而不是实际值。
This is a implementation of Fisher Yates/Durstenfeld Shuffle, but without actual creation of a array thus reducing space complexity or memory needed, when the pick size is small compared to the number of elements available.
To pick 8 numbers from 100, it is not necessary to create a array of 100 elements.
Assuming a array is created,
rnd
) from 1 to 100rnd
If a array is not created, A hashMap may be used to remember the actual swapped positions. When the second random number generated is equal to the one of the previously generated numbers, the map provides the current value in that position rather than the actual value.
例如:要生成 8 个唯一的随机数并将它们存储到数组中,您可以简单地执行以下操作:
For example: To generate 8 unique random numbers and store them to an array, you can simply do this:
使用 Set 的现代 JS 解决方案(以及平均情况在))
Modern JS Solution using Set (and average case O(n))
另一种方法是生成一个 100 个项目的数组,按升序排列并随机排序。这实际上导致了一个非常短且(在我看来)简单的片段。
Another approach is to generate an 100 items array with ascending numbers and sort it randomly. This leads actually to a really short and (in my opinion) simple snippet.
生成 100 个数字的排列,然后依次选择。
使用Knuth Shuffle(又名 Fisher-Yates shuffle)算法 。
JavaScript:
从链接复制的代码。
编辑< /strong>:
改进的代码:
潜在问题:
假设我们有 100 个数字的数组 {eg [1,2,3...100]} 并且我们在 8 次交换后停止交换;
那么大多数时候数组看起来像{1,2,3,76,5,6,7,8,...这里的数字将被打乱...10}。
因为每个数字都会以 1/100 的概率交换,所以
问题。交换前 8 个数字的概率是 8/100,而概率是 8/100。交换其他92的就是92/100。
但是,如果我们对完整数组运行算法,那么我们确信(几乎)每个条目都被交换。
否则我们就会面临一个问题:选择哪 8 个数字?
Generate permutation of 100 numbers and then choose serially.
Use Knuth Shuffle(aka the Fisher-Yates shuffle) Algorithm.
JavaScript:
CODE COPIED FROM LINK.
EDIT:
Improved code:
Potential problem:
Suppose we have array of 100 numbers {e.g. [1,2,3...100]} and we stop swapping after 8 swaps;
then most of the times array will look like {1,2,3,76,5,6,7,8,...numbers here will be shuffled ...10}.
Because every number will be swapped with probability 1/100 so
prob. of swapping first 8 numbers is 8/100 whereas prob. of swapping other 92 is 92/100.
But if we run algorithm for full array then we are sure (almost)every entry is swapped.
Otherwise we face a question : which 8 numbers to choose?
如果您想避免使用库,上述技术很好,但是根据您是否可以使用库,我建议您查看 Chance 来生成JavaScript 中的随机内容。
具体来说,为了解决您的问题,使用 Chance 非常简单:
免责声明,作为 Chance 的作者,我有点偏见;)
The above techniques are good if you want to avoid a library, but depending if you would be alright with a library, I would suggest checking out Chance for generating random stuff in JavaScript.
Specifically to solve your question, using Chance it's as easy as:
Disclaimer, as the author of Chance, I am a bit biased ;)
为了避免任何长时间且不可靠的洗牌,我会执行以下操作...
瞧 - 没有重复数字。
如果有人感兴趣,我稍后可能会发布一些实际代码。
编辑:这可能是我内心的竞争倾向,但是,看到@Alsciende 的帖子后,我忍不住发布我承诺的代码。
To avoid any long and unreliable shuffles, I'd do the following...
Voila - no repeated numbers.
I may post some actual code later, if anybody is interested.
Edit: It's probably the competitive streak in me but, having seen the post by @Alsciende, I couldn't resist posting the code that I promised.
我会这样做:
I would do this:
这是我编写的一个非常通用的函数,用于为数组生成随机唯一/非唯一整数。对于此答案,假设最后一个参数在此场景中为 true。
这里的 'tempObj' 是一个非常有用的 obj,因为生成的每个随机数都会直接检查此 tempObj 是否该密钥已经存在,如果不存在,那么我们将 i 减一,因为我们需要 1 次额外运行,因为当前随机数已经存在。
对于您的情况,运行以下
命令即可。
This is a very generic function I have written to generate random unique/non-unique integers for an array. Assume the last parameter to be true in this scenario for this answer.
Here the 'tempObj' is a very useful obj since every random number generated will directly check in this tempObj if that key already exists, if not, then we reduce the i by one since we need 1 extra run since the current random number already exists.
In your case, run the following
That's all.
将数字从 1 到 100 进行洗牌是正确的基本策略,但如果您只需要洗好 8 个数字,则无需对所有 100 个数字进行洗牌。
我不太了解 Javascript,但我相信快速创建一个包含 100 个空值的数组很容易。然后,在 8 轮中,将数组的第 n 个元素(n 从 0 开始)与从 n+1 到 99 中随机选择的元素交换。当然,任何尚未填充的元素都意味着该元素实际上已被填充原始索引加 1,所以这很容易考虑。完成 8 轮后,数组的前 8 个元素将包含 8 个洗牌后的数字。
Shuffling the numbers from 1 to 100 is the right basic strategy, but if you need only 8 shuffled numbers, there's no need to shuffle all 100 numbers.
I don't know Javascript very well, but I believe it's easy to create an array of 100 nulls quickly. Then, for 8 rounds, you swap the n'th element of the array (n starting at 0) with a randomly selected element from n+1 through 99. Of course, any elements not populated yet mean that the element would really have been the original index plus 1, so that's trivial to factor in. When you're done with the 8 rounds, the first 8 elements of your array will have your 8 shuffled numbers.
比我见过的其他答案短
shorter than other answers I've seen