Javascript 数学随机数不重复以前的数字

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6625551/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 22:31:44  来源:igfitidea点击:

math random number without repeating a previous number

javascriptrandomrepeat

提问by daryl

Can't seem to find an answer to this, say I have this:

似乎无法找到答案,说我有这个:

setInterval(function() {
    m = Math.floor(Math.random()*7);
    $('.foo:nth-of-type('+m+')').fadeIn(300);
}, 300);

How do I make it so that random number doesn't repeat itself. For example if the random number is 2, I don't want 2 to come out again.

我如何做到这一点,以便随机数不会重复。比如随机数是2,我就不想2再出来了。

回答by tskuzzy

There are a number of ways you could achieve this.

有多种方法可以实现这一目标。

Solution A: If the range of numbers isn't large (let's say less than 10), you could just keep track of the numbers you've already generated. Then if you generate a duplicate, discard it and generate another number.

解决方案 A:如果数字的范围不大(比方说小于 10),您可以跟踪您已经生成的数字。然后,如果您生成重复项,则丢弃它并生成另一个数字。

Solution B: Pre-generate the random numbers, store them into an array and then go through the array. You could accomplish this by taking the numbers 1,2,...,nand then shuffle them.

方案B:预先生成随机数,存入数组,然后遍历数组。你可以通过取数字1,2,...,n然后洗牌来实现这一点。

shuffle = function(o) {
    for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
    return o;
};

var randorder = shuffle([0,1,2,3,4,5,6]);
var index = 0;

setInterval(function() {
    $('.foo:nth-of-type('+(randorder[index++])+')').fadeIn(300);
}, 300);

Solution C: Keep track of the numbers available in an array. Randomly pick a number. Remove number from said array.

解决方案 C:跟踪数组中可用的数字。随机选择一个数字。从所述数组中删除数字。

var randnums = [0,1,2,3,4,5,6];

setInterval(function() {
    var m = Math.floor(Math.random()*randnums.length);
    $('.foo:nth-of-type('+(randnums[m])+')').fadeIn(300);
    randnums = randnums.splice(m,1);
}, 300);

回答by RobG

You seem to want a non-repeating random number from 0 to 6, so similar to tskuzzy's answer:

您似乎想要一个从 0 到 6 的非重复随机数,因此类似于 tskuzzy 的回答:

var getRand = (function() {
    var nums = [0,1,2,3,4,5,6];
    var current = [];
    function rand(n) {
        return (Math.random() * n)|0;
    }
    return function() {
      if (!current.length) current = nums.slice();
      return current.splice(rand(current.length), 1);
    }
}());

It will return the numbers 0 to 6 in random order. When each has been drawn once, it will start again.

它将以随机顺序返回数字 0 到 6。当每个都被绘制一次后,它将重新开始。

回答by CodingStix

I like Neal's answer although this is begging for some recursion. Here it is in java, you'll still get the general idea. Note that you'll hit an infinite loop if you pull out more numbers than MAX, I could have fixed that but left it as is for clarity.

我喜欢尼尔的回答,尽管这是在乞求一些递归。这是在java中,你仍然会得到一般的想法。请注意,如果您拉出的数字多于 MAX,您将遇到无限循环,我可以解决这个问题,但为了清晰起见,将其保留原样。

edit: saw neal added a while loop so that works great.

编辑:看到尼尔添加了一个while循环,所以效果很好。

public class RandCheck {
    private List<Integer> numbers;
    private Random rand;
    private int MAX = 100;

    public RandCheck(){
        numbers = new ArrayList<Integer>();
        rand = new Random();
    }

    public int getRandomNum(){
        return getRandomNumRecursive(getRand());
    }

    private int getRandomNumRecursive(int num){
        if(numbers.contains(num)){
            return getRandomNumRecursive(getRand());
        } else {
            return num;
        }
    }

    private int getRand(){
        return rand.nextInt(MAX);
    }

    public static void main(String[] args){
        RandCheck randCheck = new RandCheck();

        for(int i = 0; i < 100; i++){
            System.out.println(randCheck.getRandomNum());
        }
    }
}

回答by user2514880

not sure if its too late, but would still like to add--

不确定是否为时已晚,但仍想补充--

var RecordKeeper = {};

SRandom = function () {
    currTimeStamp = new Date().getTime();
    if (RecordKeeper.hasOwnProperty(currTimeStamp)) {
        RecordKeeper[currTimeStamp] = RecordKeeper[currTimeStamp] + 1;
        return currTimeStamp.toString() + RecordKeeper[currTimeStamp];
    }
    else {
        RecordKeeper[currTimeStamp] = 1;
        return currTimeStamp.toString() + RecordKeeper[currTimeStamp];
    }
}

this basically uses timestamp (every millisecond) to always generate a unique number.

这基本上使用时间戳(每毫秒)来始终生成一个唯一的数字。

回答by Tim Cutting

Here's a simple fix, if a little rudimentary:

这是一个简单的修复,如果有点简陋:

if(nextNum == lastNum){
    if (nextNum == 0){nextNum = 7;} 
    else {nextNum = nextNum-1;}
}

If the next number is the same as the last simply minus 1 unless the number is 0 (zero) and set it to any other number within your set (I chose 7, the highest index).

如果下一个数字与上一个数字相同,则只需减去 1,除非数字为 0(零)并将其设置为您的集合中的任何其他数字(我选择了 7,最高索引)。

I used this method within the cycle function because the only stipulation on selecting a number was that is musn't be the same as the last one.

我在循环函数中使用了这种方法,因为对选择数字的唯一规定是不能与最后一个相同。

Not the most elegant or technically gifted solution, but it works :)

不是最优雅或技术上最有天赋的解决方案,但它有效:)

回答by Konrad

Use sets. They were introduced to the specification in ES6. A set is a data structure that represents a collection of unique values, so it cannot include any duplicate values. I needed 6 random, non-repeatable numbers ranging from 1-49. I started with creating a longer set with around 30 digits (if the values repeat the set will have less elements), converted the set to array and then sliced it's first 6 elements. Easy peasy. Set.lengthis by default undefinedand it's useless that's why it's easier to convert it to an array if you need specific length.

使用套装。在 ES6 规范中引入了它们。集合是表示唯一值集合的数据结构,因此它不能包含任何重复值。我需要 6 个随机的、不可重复的数字,范围从 1 到 49。我首先创建了一个大约 30 位数字的较长集合(如果值重复,则该集合的元素将更少),将集合转换为数组,然后将其切片为前 6 个元素。十分简单。Set.length默认情况下是未定义的,它是无用的,这就是为什么如果您需要特定长度,将其转换为数组会更容易。

let randomSet = new Set();
for (let index = 0; index < 30; index++) {
        randomSet.add(Math.floor(Math.random() * 49) + 1) 
    };
let randomSetToArray = Array.from(randomSet).slice(0,6);
console.log(randomSet);
console.log(randomSetToArray);

回答by Alexander Beletsky

could you try that,

你可以试试吗

setInterval(function() {
    m = Math.floor(Math.random()*7);
    $('.foo:nth-of-type(' + m + ')').fadeIn(300);
}, 300);

回答by aardvarkk

Generally my approach is to make an array containing all of the possible values and to:

通常,我的方法是制作一个包含所有可能值的数组,然后:

  1. Pick a random number <= the size of the array
  2. Remove the chosen element from the array
  3. Repeat steps 1-2 until the array is empty
  1. 选择一个随机数 <= 数组的大小
  2. 从数组中删除所选元素
  3. 重复步骤 1-2 直到数组为空

The resulting set of numbers will contain all of your indices without repetition.

生成的一组数字将包含您的所有索引而不会重复。

Even better, maybe something like this:

更好的是,也许是这样的:

var numArray = [0,1,2,3,4,5,6];
numArray.shuffle();

Then just go through the items because shuffle will have randomized them and pop them off one at a time.

然后只需浏览这些项目,因为 shuffle 会将它们随机化并一次弹出一个。

回答by Naftali aka Neal

you can do this. Have a public array of keys that you have used and check against them with this function:

你可以这样做。拥有您使用过的公共密钥数组,并使用此函数检查它们:

function in_array(needle, haystack)
{
    for(var key in haystack)
    {
        if(needle === haystack[key])
        {
            return true;
        }
    }

    return false;
}

(function from: javascript function inArray)

(功能来自:javascript 函数 inArray

So what you can do is:

所以你可以做的是:

var done = [];
setInterval(function() {
    var m = null;
    while(m == null || in_array(m, done)){
       m = Math.floor(Math.random()*7);
    }
    done.push(m);
    $('.foo:nth-of-type('+m+')').fadeIn(300);
}, 300);

This code will get stuck after getting all seven numbers so you need to make sure it exists after it fins them all.

获取所有七个数字后,此代码将卡住,因此您需要确保它在全部完成后存在。