Javascript:每次随机5个数字,直到所有数字都被使用过才重复。

7
我正在使用以下代码为页面上的每个图片分配一个随机类(五个中的一个)。
$(this).addClass('color-' + (Math.floor(Math.random() * 5) + 1));

它的工作很好,但我希望它永远不会有两个相同的类在一行中。
更好的方法是永远不会有两个连续相同的类,并且它也不会在使用所有5个类之前重复使用任何一个类...换句话说,从数组中删除每个已使用的类,直到它们全部被使用,然后重新开始,在上一个5个颜色和下一个5个颜色中,不允许最后一个和第一个颜色相同。
希望这有意义,谢谢您提前的帮助。

4
创建一个从15的范围,然后打乱该数组。 - elclanrs
4个回答

20

您需要创建一个可能值的数组,并每次从该数组中检索随机索引以使用其中一个值,然后将其从数组中删除。

这是一个通用的随机函数,它不会重复使用所有的值,您可以调用此函数,然后只需将此索引添加到类名的末尾即可。

var uniqueRandoms = [];
var numRandoms = 5;
function makeUniqueRandom() {
    // refill the array if needed
    if (!uniqueRandoms.length) {
        for (var i = 0; i < numRandoms; i++) {
            uniqueRandoms.push(i);
        }
    }
    var index = Math.floor(Math.random() * uniqueRandoms.length);
    var val = uniqueRandoms[index];

    // now remove that value from the array
    uniqueRandoms.splice(index, 1);

    return val;

}

工作演示:http://jsfiddle.net/jfriend00/H9bLH/


所以,你的代码只需要这样:

$(this).addClass('color-' + (makeUniqueRandom() + 1));

这是一个面向对象的表单,可以让您在应用程序的不同位置使用多个表单:

// if only one argument is passed, it will assume that is the high
// limit and the low limit will be set to zero
// so you can use either r = new randomeGenerator(9);
// or r = new randomGenerator(0, 9);
function randomGenerator(low, high) {
    if (arguments.length < 2) {
        high = low;
        low = 0;
    }
    this.low = low;
    this.high = high;
    this.reset();
}

randomGenerator.prototype = {
    reset: function() {
        this.remaining = [];
        for (var i = this.low; i <= this.high; i++) {
            this.remaining.push(i);
        }
    },
    get: function() {
        if (!this.remaining.length) {
            this.reset();
        }
        var index = Math.floor(Math.random() * this.remaining.length);
        var val = this.remaining[index];
        this.remaining.splice(index, 1);
        return val;        
    }
}

示例用法:

var r = new randomGenerator(1, 9);
var rand1 = r.get();
var rand2 = r.get();

演示: http://jsfiddle.net/jfriend00/q36Lk4hk/


如果您能向我展示如何“调用此函数”并将索引添加到类名中,我将不胜感激。我没有JavaScript的经验,但本周购买了一本书,今天刚开始阅读,所以我正在努力解决这个问题。再次感谢,您发布的内容已经非常有帮助了。 - user2860129
一种改进方法是保留原始数组并为拼接制作一份副本。当所有成员都被拼接时,再制作另一份副本(如果需要的话)。 - RobG
@RobG - 当需要时,为什么复制比创建新的更容易? - jfriend00
因为原始数据可能不仅仅是数字序列,或者像“颜色1”,“颜色2”等具有某种顺序。 - RobG
@RobG - 好的,我正在追求一种通用的数字生成方法,可以在事后与任何想要的文本组合使用。 - jfriend00
显示剩余2条评论

3

您可以使用数组和 splice 方法来进行类似以下这样的操作:

var classes = ["color-1", "color-2", "color-3", "color-4", "color-5"];
for(i = 0;i < 5; i++){
  var randomPosition = Math.floor(Math.random() * classes.length);
  var selected = classes.splice(randomPosition,1);
  console.log(selected);
  alert(selected);
}

1
var used = [];
var range = [0, 5];

var generateColors = (function() {
    var current;
    for ( var i = range[0]; i < range[5]; i++ ) {

        while ( used.indexOf(current = (Math.floor(Math.random() * 5) + 1)) != -1 ) ;
        used.push(current);
        $("   SELECTOR     ").addClass('color-' + current);
    }
});

1

为了解释我对jfriend00优秀回答的评论,你可以拥有一个函数,以随机顺序返回集合的成员,直到所有成员都被返回,然后重新开始,例如:

function RandomList(list) {
  var original = list;
  this.getOriginal = function() {
    return original;
  }
}

RandomList.prototype.getRandom = function() {
  if (!(this.remainder && this.remainder.length)) {
    this.remainder = this.getOriginal().slice();
  }
  return this.remainder.splice(Math.random() * this.remainder.length | 0,1);
}

var list = new RandomList([1,2,3]);

list.getRandom(); // returns a random member of list without repeating until all
                  // members have been returned.

如果可以硬编码列表,您可以将原始列表保存在一个闭包中,例如:
var randomItem = (function() {
  var original = [1,2,3];
  var remainder;
  return function() {
    if (!(remainder && remainder.length)) {
      remainder = original.slice();
    }
    return remainder.splice(Math.random() * remainder.length | 0, 1);
  };
}());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接