根据范围选择随机选项

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费信用额度!

我有三个选项,需要随机选择一个(在 JavaScript 中)。但不是完全随机的。我希望第一个选项有 10% 的几率,第二个选项有 20% 的几率,第三个选项有 70% 的几率。

以下是一些实现方法。

假设数据如下

var choices = [
  [10, "apples"],
  [20, "oranges"],
  [70, "bananas"] 
];

此外,我们还为迭代器和随机数等内容设置了作用域变量。我们不妨将这段代码视为概念性代码,而非生产代码。

在最小值和最大值之间测试

我首先想到的是生成一个 1-100 之间的随机数,然后测试该数字是否在…

  • 1-10 之间(苹果)
  • 11-30 之间(橙子)
  • 31-100 之间(香蕉)

获取这些最小值和最大值有点冗长。您运行一个循环来遍历所有选项。第一个选项的最小值为零,其余选项的最小值为所有先前选项的总和。最大值为当前选项和所有先前选项的总和。

在循环的每次迭代中,您都会测试随机数是否在刚刚生成的范围内。如果是,则设置最终选项并中断。否则,执行另一次迭代。

function pickChoice() {

  rand = Math.floor(Math.random() * 100);
  choice = -1;
  
  for (i = 0; i < choices.length; i++) {

    // set up min
    if (i === 0) {
      min = 0;
    } else {
      min = 0;
      // add up all the values so far
      for (i2 = 0; i2 < i; i2++) {
        min += choices[i2][0];
      }
      // one higher
      min++;
    }

    // set up max
    if (i === 0) {
      max = choices[i][0];
    } else {
      max = 0;
      // add up all the values so far
      for (i2 = 0; i2 < i + 1; i2++) {
        max += choices[i2][0];
      }
    }

    if (rand >= min && rand <= max) {
      choice = i;
      break;
    }

  }
  
  // If the choice is still -1 here, something went wrong...
  
};

查看 CodePen 上 Chris Coyier (@chriscoyier) 的笔 数组项目的百分比几率

测试是否高于最小值

David DeSandro 有一个更巧妙的想法(当然)。从一开始就为每个选项指定一个最小值。每个选项的最小值为所有先前选项的总和。因此数据变为

  • 苹果:0
  • 橙子:10
  • 香蕉:30

然后生成一个随机数,遍历选项,如果随机数高于最小值,则将选择设置为该选项。在这个循环中,选择可能会被设置多次,但最终会选择正确的选项。

function pickChoice() {
  var rand = Math.random() * 100, pick, choice, i;
  // go through choices, update pick if rand is above bottom percent threshold
  for ( i = 0, len = choices.length; i < len; i++ ) {
    choice = choices[i];
    if ( rand > choice.percent ) {
      pick = choice;
    }
  }
  return pick;
}

David 还根据其分支中的 HTML 中的值设置数据。

查看 CodePen 上 David DeSandro (@desandro) 的笔 数组项目的百分比几率

构建一个包含所有可能性的新数组

George Papadakis 使用另一种方法制作了一个快速演示。构建一个新数组,其中每个选项都按比例正确的次数表示。因此,根据我们的数据,可以简化为

  • 新数组中 1 个项目是苹果
  • 新数组中 2 个项目是橙子
  • 新数组中 7 个项目是香蕉

然后,当您生成一个随机数来选择一个项目时,只需从新数组中直接选择该项目,例如 choices[rand]

// quick'n'dirty
NodeList.prototype.map = Array.prototype.map;

var choices = [], 
  lis = document.querySelectorAll('li')
    .map(function (item) {
      var percent = parseFloat(item.querySelector('span').textContent) / 10,
        label = item.querySelector('strong').textContent;
             
      for (var i = 0; i < percent; i++) {
        choices.push(label)
      }
    });

function pick() {
  var rnd = parseInt(Math.random() * 10);
  document.querySelector('div.choice').innerHTML = choices[rnd];
}

查看 CodePen 上 George Papadakis (@phaistonian) 的笔 数组项目的百分比几率

更多?

您可能可以将所有这些想法混合到其他解决方案中。或者用完全不同的方法来解决这个问题。看到同一个问题的不同解决方案总是很有趣的!

我的实际用例是需要随机化一些广告,但需要基于百分比份额而不是简单的随机拆分。任何一种方法都可以做到这一点。