You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Sheets脚本实现赛事配对:解决空白与同行重复问题

Google Sheets 赛事对阵配对脚本调试方案

需求说明

  • 利用Google Sheets脚本生成赛事对阵配对:首列为选手名单,后续列对应各轮次的对手列表
  • 必须过滤空白单元格,防止排序后出现空白行
  • 确保每行中选手姓名与对手姓名不重复,若出现重复则重新打乱数组直至符合要求

遇到的问题

使用filter(String)过滤空白单元格后,执行setValues时触发数据行数与目标范围行数不匹配的错误,无法彻底消除空白区域。后续将代码迁移至测试表并添加两轮配对逻辑,但仍存在需要调试的问题。

初始代码

function shuffleRange() {
  var sheet = SpreadsheetApp.getActive().getSheetByName('SETUP');
  var range = sheet.getRange('A31:A')
  var range2 = sheet.getRange('C31:C');
  range2.clearContents;
  range2.setValues(shuffleArray(range.getValues()));
}

function shuffleArray(array) {
  var i, j, temp;
  for (i = array.length - 1; i > 0; i--) {
    j = Math.floor(Math.random() * (i+1));
    temp = array[i];
    array[i] = array[j];
    array[j] = temp;
  }
  return array;
}

更新后的测试代码

注:代码已迁移至测试表,对应工作表名称和范围已调整

function shuffleRange() {
  var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet4');
  var range = sheet.getRange('A1:A40')
  var v = range.getValues().filter(String);      
        
      //Match 1
  var values = shuffleArray1(v);
  while (v.length != [...new Set(values.map(([a]) => a))].length) {
    values = shuffleArray1(v);  
  }
  range.offset(0, 1, values.length).setValues(values);

      //Match 2
  var values2 = shuffleArray2(v);
  while (v.length != [...new Set(values2.map(([a]) => a))].length) {
    values = shuffleArray2(v);  
  }
  range.offset(0, 2, values.length).setValues(values2);
}

function shuffleArray1(array) {
  var i, j, temp;
  for (i = array.length - 1; i > 0; i--) {
    j = Math.floor(Math.random() * (i+1));
    temp = array[i];
    array[i] = array[j];
    array[j] = temp;
  }
  return array;
}

function shuffleArray2(array) {
  var u, v, temp;
  for (u = array.length - 3; u > 0; u--) {
    v = Math.floor(Math.random() * (u+2));
    temp = array[u];
    array[u] = array[v];
    array[v] = temp;
  }
  return array;
}

问题修复与优化方案

1. 解决setValues行数不匹配问题

原代码中range.getValues()会获取整列所有单元格(含大量空白行),过滤后数组长度远小于原范围行数,导致setValues报错。正确做法:

  • 过滤空白后,仅针对有效数据的范围写入值
  • 写入前清空目标列中对应有效数据行的内容,而非整列

2. 修复重复姓名判断逻辑

原代码判断逻辑错误,当前是检查打乱后的数组是否有重复选手,实际需求是每行的选手与对应对手姓名不重复,需改为逐行对比原数组和打乱后的数组,确保原选手[i] !== 对手[i]。

3. 优化洗牌函数

无需定义多个洗牌函数,一个通用函数即可满足多轮配对需求,减少代码冗余。

优化后的完整代码

function generateMatchups() {
  const sheet = SpreadsheetApp.getActive().getSheetByName('Sheet4');
  // 获取首列数据并严格过滤空白
  const rawData = sheet.getRange('A1:A40').getValues();
  const players = rawData.filter(row => row[0].toString().trim() !== '');
  const playerCount = players.length;
  if (playerCount === 0) return;

  // 通用洗牌函数(创建数组副本,不修改原数据)
  function shuffleArray(arr) {
    const newArr = [...arr];
    for (let i = newArr.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [newArr[i], newArr[j]] = [newArr[j], newArr[i]];
    }
    return newArr;
  }

  // 生成符合要求的对阵列表
  function generateValidMatchup(baseArr) {
    let matchup;
    do {
      matchup = shuffleArray(baseArr);
      // 逐行检查是否无重复姓名
      let isValid = true;
      for (let i = 0; i < playerCount; i++) {
        if (baseArr[i][0] === matchup[i][0]) {
          isValid = false;
          break;
        }
      }
      if (isValid) break;
    } while (true);
    return matchup;
  }

  // 写入第一轮对阵到B列
  const matchup1 = generateValidMatchup(players);
  sheet.getRange(1, 2, playerCount, 1).clearContent().setValues(matchup1);
  // 写入第二轮对阵到C列
  const matchup2 = generateValidMatchup(players);
  sheet.getRange(1, 3, playerCount, 1).clearContent().setValues(matchup2);
}

代码说明

  • 过滤空白时去除首尾空格,避免误过滤含空格的无效单元格
  • 洗牌操作创建数组副本,不破坏原选手列表
  • 有效性检查精准匹配需求,确保每行选手与对手姓名不重复
  • 仅针对有效选手数量的范围写入数据,彻底解决行数不匹配问题

内容的提问来源于stack exchange,提问作者Tweak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 20:30:41