js根据一个总数去生成随机数?

let arr = [
  { id: 1, test: 6 }, // 生成6列数据
  { id: 2, test: 4 }, // 生成4列数据
  { id: 3, test: 5 }, // 生成5列数据
]

test的之和为15;
假如我总数为29,
生成15个框(根据test的之和15就生成15个框)的数据:如下图()

下面写的这个方法:在第14个框的值为27-29之间的数据,第15个框的值为负数了,请问这个方法能优化下吗?或者还有其他方法吗?

      function filterate(arr, num = 29) {
        let count = list.reduce((n, i) => n + Number(i.test), 0)
        let step = Math.ceil(num / count);
        let data = arr.map((item, index) => {
          return Array.from({length: Number(item.test)}).map(citem => {
            return {
              min: 0,
              max: 0,
              num: 0,
            }
          })
        })
        let max = Math.max(...list.map(i => Number(i.test)));
        let value = 0;
        let current = 1;
        for (let index = 0; index < max; index++) {
          data.forEach((item, k) => {
            if(item[index]){
              item[index].min = value + 1
              value += step
              if(num < value + step){
                value = num
              }
              item[index].max = num < value + step ? num : value
              item[index].num= Math.floor(Math.random() * (item[index].max - item[index].min + 1)) + item[index].min
            }
          })
        }
        return data;
      }
阅读 2.4k
avatarAI BotBETA

从你给出的描述和代码来看,你的目标是根据一个总数(例如29)和一组对象(每个对象表示需要生成的数据列数),生成一系列随机数,并确保总数不超过给定的总数。然而,你的当前方法在处理剩余数值分配时存在一些问题,特别是在接近总数末尾时可能导致负数或超出预期范围的值。

下面是一个优化的方法,该方法通过迭代每个对象的列数,并逐个分配随机数,同时确保总数不超过给定的值:

function generateRandomData(arr, total) {
    let currentTotal = 0;
    let remaining = total;
    const result = arr.map(item => {
        const data = Array.from({ length: item.test }, () => 0);
        let allocated = 0;

        // 分配每个列的随机数,直到总数用尽或该列的随机数分配完毕
        for (let i = 0; i < item.test; i++) {
            if (remaining <= 0) break; // 如果剩余数为0,则停止分配

            const max = Math.min(remaining, total - currentTotal); // 最大不超过剩余数和总数
            const randomNum = Math.floor(Math.random() * (max - 1)) + 1; // 生成1到max之间的随机数

            data[i] = randomNum;
            currentTotal += randomNum;
            remaining -= randomNum;
            allocated++;

            // 如果已经分配了当前对象的所有列或剩余数为0,则跳出循环
            if (allocated === item.test || remaining <= 0) break;
        }

        return data;
    });

    // 检查是否所有数值都被分配(理论上不应该发生,除非total小于所有test的总和)
    if (currentTotal !== total) {
        console.error('Failed to allocate all numbers, check total and test sums.');
    }

    return result;
}

// 示例用法
let arr = [
    { id: 1, test: 6 },
    { id: 2, test: 4 },
    { id: 3, test: 5 },
];

const total = 29;
const result = generateRandomData(arr, total);
console.log(result);

这个方法首先初始化一些变量来跟踪当前的总数和剩余的可分配数。然后,它遍历每个对象,并为每个对象的每列生成一个随机数。随机数是根据剩余数和当前已分配的总数来计算的,以确保不会超过总数。如果剩余数不足以继续分配,则停止分配。

这种方法更加直观且易于管理,同时避免了在接近总数末尾时出现负数或超出范围的值。

1 个回答

你中间的if(num < value + step){value = num}改变了value的值

function filterate(list, num = 29) {
    let data = list.map((item, index) => {
      return Array.from({length: Number(item.test)}).map(citem => {
        return {
          min: 0,
          max: 0,
          num: 0,
        }
      })
    })
    
    let max = Math.max(...list.map(i => Number(i.test)));
    let value = 0;
    let current = 1;
    let count = list.reduce((n, i) => n + Number(i.test), 0)
    
    for (let index = 0; index < max; index++) {
      data.forEach((item, k) => {
        if(item[index]){
            
          let step = num / count | 0 // 下取整
          count-- //循环计算step,确保step在剩下的始祖中平均分配
          num-=step
            
          item[index].min = value + 1
          value += step
          item[index].max = value
          item[index].num= Math.floor(Math.random() * (item[index].max - item[index].min + 1)) + item[index].min
        }
      })
    }
    return data;
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏