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

Posted

技术标签:

【中文标题】如何在不替换条件的情况下随机化?【英文标题】:How to randomize without replacement with conditions? 【发布时间】:2021-07-16 19:15:40 【问题描述】:

我有许多嵌入的图像,我将它们随机化 4 次而不进行替换(一旦看到图像,您将无法再次看到它)。我想添加一个条件,表明无法看到一组附加图像(不仅是先前选择的图像)。这些图片与所选图片具有相似的特征。

演示:

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

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

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

现在假设我画了 var BF1,那么下一组可能的 var 将是:

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)

【问题讨论】:

过滤和结束 【参考方案1】:

您绝对可以通过多种方式实现这一点,但无论您使用什么,您都需要以某种能力执行以下 3 个步骤(我将它们分成单独的方法,但您可以根据需要将它们组合起来)看合适):

    随机播放列表 选择一个项目 过滤掉与pick匹配的项目(在本例中为相同编号的项目)

您已经涵盖了随机播放程序,因此只剩下选择和过滤器。

对于选择,我只是使用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-3 次,直到没有选择余下

【讨论】:

【参考方案2】:

您可以使用循环和随机数对数组进行洗牌,然后在另一个循环中提取结果数组中的第一个图像,在字符串末尾使用数字过滤数组

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

【讨论】:

以上是关于如何在不替换条件的情况下随机化?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不重复预定义三元组中的特定元素的情况下随机化向量?

如何在不使用左连接的情况下根据“OR”条件对数据框进行子集化? [复制]

是否可以在不子类化的情况下替换 UIWebView 中现有方法的主体

如何在不重复整数的情况下随机创建 ID 列?

组合:如何在不完成原始发布者的情况下替换/捕获错误?

如何在不替换旧文本的情况下向 TextView 添加文本?