【问题标题】:math random number without repeating a previous number数学随机数而不重复先前的数字
【发布时间】:2011-10-01 07:38:38
【问题描述】:

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

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

如何使随机数不会重复。比如随机数是2,我不希望2再出来。

【问题讨论】:

  • 不再来了还是下次再来?
  • @Gedrox 不确定我是否关注你?
  • 接收数字 2 > 4 > 2 > 4 是否可以,或者您不想要?
  • 那么你真正想要的不是一个随机数,而是一个随机顺序的数字序列?那是完全不同的事情。 Tskuzzy 似乎对此有正确的想法。
  • 只需创建一个数字池作为数组并从中取出一个直到它为空。

标签: javascript random repeat


【解决方案1】:

我想补充--

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];
    }
}

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

【讨论】:

    【解决方案2】:

    一种生成不同数字列表的简单方法,无论大小或数字如何:

         function randomNumber(max) {
              return Math.floor(Math.random() * max + 1);
            }
            
            const list = []
            while(list.length < 10 ){
                let nbr = randomNumber(500)
                if(!list.find(el => el === nbr)) list.push(nbr) 
            }
            
            console.log("list",list)

    【讨论】:

      【解决方案3】:

      使用集合。它们被引入到 ES6 的规范中。集合是表示唯一值集合的数据结构,因此它不能包含任何重复值。我需要 6 个随机的、不可重复的数字,范围从 1 到 49。我开始创建一个大约 30 位的较长集合(如果值重复,该集合将包含更少的元素),将集合转换为数组,然后对其前 6 个元素进行切片。十分简单。 Set.length 默认是 undefined 并且它没有用,这就是为什么如果你需要特定的长度更容易将它转换为数组。

      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);
      

      【讨论】:

        【解决方案4】:

        您可以通过多种方式实现这一目标。

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

        解决方案 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);
        

        解决方案 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);
        

        【讨论】:

        • +1。我修复了解决方案 B 中的一个明显错误(将 index++ 更改为 randorder[index++]);希望没事。
        • 谢谢,当场就写了这些:)
        • 您是否复制了我提供的链接中描述的shuffle() 函数? snippets.dzone.com/posts/show/849shuffle() 不是标准的 javascript 函数。 :)
        • @tskuzzy - 太棒了,非常感谢!稍后我将对这些答案进行更多研究。毫无意义地询问和依赖其他人,你没有那样的地方。谢谢!
        • 请不要推荐解决方案 A。当“未使用”的数字很少并且您循环大量重试直到 math.random 偶然发现其中一个时,它很容易导致性能大幅下降。
        【解决方案5】:

        这里有一个简单的修复,如果有点初级:

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

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

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

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

        【讨论】:

          【解决方案6】:

          您似乎想要一个从 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);
              }
          }());
          

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

          【讨论】:

            【解决方案7】:

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

            编辑:看到 neal 添加了一个 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());
                    }
                }
            }
            

            【讨论】:

            • 抱歉,您的代码是用 Java 编写的。问题是询问Javascript。无论如何,为努力+1 :)
            【解决方案8】:

            一般来说,我的方法是创建一个包含所有可能值的数组,然后:

            1. 选择一个随机数
            2. 从数组中移除选中的元素
            3. 重复步骤 1-2,直到数组为空

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

            更好,也许是这样的:

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

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

            【讨论】:

            • 好吧,我被卡住了,我之前没有处理过 jquery 中的数组。 :~|
            • 您用来调用 JQuery 函数的代码已经是 JavaScript,而这只是一个 JavaScript 数组。你可以的!
            【解决方案9】:

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

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

            (函数来自:javascript function inArray

            所以你可以做的是:

            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);
            

            这段代码在得到所有七个数字后会卡住,所以你需要确保它在它全部结束后存在。

            【讨论】:

            • 肯定while 循环永远不会执行,因为您设置了m=null 并且循环条件之一是m != null,还是我遗漏了什么?
            • jQuery 中已经内置了一个inArray()
            • @JackFranklin,抱歉我打字快,我修好了
            • @Stefan,可能需要一些延迟......是的,我忘记了 jQuery 的 inArray 它的使用方式与我的示例相同。
            • 完全矫枉过正。您只需要done={}; 并用简单的m in done 替换您的in_array 方法,而不是.push() 使用done[m]=1; 虽然我没有投反对票,但这仍然是唯一可行的解​​决方案。
            【解决方案10】:

            你可以试试吗,

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

            【讨论】:

            • 不,那行不通,这是我在示例问题中的错误,抱歉。这实际上就是我要提出的问题。
            猜你喜欢
            • 2020-10-15
            • 2013-01-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-23
            • 1970-01-01
            • 2018-07-03
            相关资源
            最近更新 更多