如何在没有条件替换的情况下随机化?

How to randomize without replacement with conditions?

我有一些嵌入的图像,我将它们随机化了 4 次而没有替换(一旦图像被看到,你就不能再看到它)。我想添加一个条件,这表明无法看到一组附加图像(不仅是之前选择的图像)。这些图像与所选图像具有相似特征。

演示:

假设我有以下变量数组: BF1, BA1, BF2, BA2, BF3, BA3

我想从数组中随机抽取 3 个变量(图像)而不进行替换,并且我还希望从下一个数组中删除编号为 2(同一组)的变量。所以,如果第一次绘制的 var 是 BF2,那么下一次绘制将来自以下数组:

BF1, BA1, BF3, BA3(只能随机出现一个选项)

现在假设我绘制了变量 BF1,那么下一组可能的变量将是:

BF3, BA3.

我希望这是有道理的。这是我到目前为止没有替换的绘图代码:

function shuffle(array){
  var counter = array.length,
  temp, index;
  while (counter > 0){
  index = Math.floor(Math.random() * counter);
  counter = counter-1;
  temp = array[counter];
  array[counter] = array[index];
  array[index] = temp;
  }
  return array;


var myArray = [BF1,BA1,BF2, BA2, BF3,BA3, BA4, BF4, BA5, BF5, BF6, BA6, BF7, BA7, BA8, BF8, BA9, BF9, BF10, BA10, BA11, BF11, BA12, BF12, BA13, BF13, BA14, BF14, BA15, BF15, BA16, BF16, BA17, BF17, BA18, BF18, BA19, BF19, BA20, BF20, BA21, BF21, BF22, BA23, BF23, BA24, BF24, BA25, BF25, BA26, BF26, BA27, BF27, BA28, BF28, BA29, BF29, BA30, BF30, BA31, BF31, BA32, BF33, BA33, BA34, BF35, BA35, BA36, BF36];
    
shuffle(myArray)

您可以使用循环和随机数打乱数组,然后在另一个循环中提取结果数组中的第一张图像,过滤字符串末尾带有数字的数组

var myArray="BF1, BA1, BF2, BA2, BF3, BA3, BA4, BF4, BA5, BF5, BF6, BA6, BF7, BA7, BA8, BF8, BA9, BF9, BF10, BA10, BA11, BF11, BA12, BF12, BA13, BF13, BA14, BF14, BA15, BF15, BA16, BF16, BA17, BF17, BA18, BF18, BA19, BF19, BA20, BF20, BA21, BF21, BF22, BA23, BF23, BA24, BF24, BA25, BF25, BA26, BF26, BA27, BF27, BA28, BF28, BA29, BF29, BA30, BF30, BA31, BF31, BA32, BF33, BA33, BA34, BF35, BA35, BA36, BF36";

function shuffle(a) {
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

const arr = shuffle(myArray.split(','));

function draw(a, times) {
  let res =[]
  for (let i = 1; i <= times; i++) {
    let str = a[0]
    res.push(str)
    a = a.filter(a => parseInt(a.match(/\d+$/)[0], 10) !== parseInt(str.match(/\d+$/)[0], 10))
  }
  return res
}

 console.log(draw(arr, 4))

您当然可以通过多种方式实现这一点,但无论您使用什么,您都需要以某种身份执行以下 3 个步骤(我将它们拆分为单独的方法,但您可以将它们组合起来如您所愿):

  1. 随机播放列表
  2. 选择一个项目
  3. 筛选出符合选择的项目(在本例中,具有相同编号的项目)

您已经涵盖了洗牌例程,所以只剩下挑选和过滤器了。

对于选择,我只是使用 Math.random 从列表中随机拉取一个成员:

return array[Math.floor(Math.random() * array.length)];

对于过滤器,我使用 Array.prototype.filter 来提取所需的项目。在这种情况下,对于字符串,我从字符串中解析出数字,然后删除数组中与最后一次选择具有相同数字的所有项目:

return array.filter(el => +el.match(/\d+/).join() != +picked.match(/\d+/).join());

但是对于实际图像,您只需将其替换为您阅读图像标签的方式即可。

例子

这是完整的工作示例,首先是精选列表,然后是经过排序的精选数组,显示它们都已被使用。

var imageList = ['BF1', 'BA1', 'BF2', 'BA2', 'BF3', 'BA3', 'BA4', 'BF4', 'BA5', 'BF5', 'BF6', 'BA6', 'BF7', 'BA7', 'BA8', 'BF8', 'BA9', 'BF9', 'BF10', 'BA10', 'BA11', 'BF11', 'BA12', 'BF12', 'BA13', 'BF13', 'BA14', 'BF14', 'BA15', 'BF15', 'BA16', 'BF16', 'BA17', 'BF17', 'BA18', 'BF18', 'BA19', 'BF19', 'BA20', 'BF20', 'BA21', 'BF21', 'BF22', 'BA23', 'BF23', 'BA24', 'BF24', 'BA25', 'BF25', 'BA26', 'BF26', 'BA27', 'BF27', 'BA28', 'BF28', 'BA29', 'BF29', 'BA30', 'BF30', 'BA31', 'BF31', 'BA32', 'BF33', 'BA33', 'BA34', 'BF35', 'BA35', 'BA36', 'BF36'];

var selection = imageList.slice();

var picked = [];

function shuffle(array) {
  var counter = array.length, temp, index;
  while (counter > 0) {
    index = Math.floor(Math.random() * counter);
    counter = counter - 1;
    temp = array[counter];
    array[counter] = array[index];
    array[index] = temp;
  }
  return array;
}

function pick(array) {
  return array[Math.floor(Math.random() * array.length)];
}

function filterPicked(picked, array) {
  return array.filter(el => +el.match(/\d+/).join() != +picked.match(/\d+/).join());
}

while (selection.length) {
  // 1. Shuffle
  shuffle(selection);
  // 2. Pick
  picked.push(pick(selection));
  // 3. Filter
  selection = filterPicked(picked[picked.length-1], selection);
}

console.log(`Picks: [${picked.join(', ')}]`);

console.log(`Sorted picks: [${picked.sort((a, b) => +a.match(/\d+/).join() - +b.match(/\d+/).join()).join(', ')}]`);

循序渐进

  1. 打乱选择数组(完整数组或所有选择的副本)
  2. 从选择数组中选择一个项目,将其推入选择数组
  3. 过滤选择数组以删除与上次选择匹配的项目
  4. 对每个新过滤的数组重复 1-3,直到没有选择剩余