Excelscript:复制重复行的信息

enxuqcxy  于 2023-08-08  发布在  其他
关注(0)|答案(1)|浏览(79)

我通常在Excel中使用VBA来自动执行繁重的任务,例如清理数据表,但我想尝试Excel脚本。由于对JavaScript不太熟悉,我想我应该尝试ChatGPT来完成繁重的工作。我认为它会工作除了一对夫妇的错误,我需要帮助。
我的数据表包含以下内容(以及其他列):
| 地点2|地点3|地点4|地点5|地点6|地点7|产品编号|属性1|属性2|属性3|属性4|属性5|属性6|属性7|属性8|属性9| Attribute 9 |
| --|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--| ------------ |
| ||||||一个|价值|价值|价值|价值|价值|价值|价值|价值|价值| value |
| | ||||一个|||价值|价值|价值||价值||价值|| value |
| | | ||一个|价值2|价值2|价值2|价值||价值|||价值||| value |
| | | | 一个|价值3|价值2||||||||||||
| | | | | 价值|价值|价值|价值|价值|价值|价值|价值| value | value | value | value | value |
| | | | | | |价值3|价值3|价值2|价值||| value3 | value3 | value2 | value ||
| | | | | | | ||价值4|价值4| value3 | value3 | value ||| value4 | value4 |
我有一个具有属性的产品,但该产品在不同位置重复。对于产品ID,所有位置的所有属性都应该相同,但它们并非如此。该脚本查找重复的ProductID组,并按优先顺序遍历位置,选择应该具有良好属性的行(本例中的位置1)。然后,它将这些属性值复制到具有相同重复产品ID的其他行(即,所有7行应具有相同的属性值)。
以下是ChatGPT生成的完整Excelscript。

function main(workbook: ExcelScript.Workbook) {
  // Step 1: Find columns with text in row 1 and store the text with associated column index in an array
  const currentSheet = workbook.getActiveWorksheet();
  const headerRow = currentSheet.getRange("1:1").getValues()[0]; // Get values of row 1
  const columnIndexes: { [key: string]: number } = {};

  for (let i = 0; i < headerRow.length; i++) {
    const columnName = headerRow[i].toString().trim();
    if (columnName !== "") {
      columnIndexes[columnName] = i + 1; // Store the column index
    }
  }

  // Step 2: Find the index for the column called "Product ID"
  const productIDIndex = columnIndexes["Product ID"];
  if (!productIDIndex) {
    console.log("Column 'Product ID' not found.");
    return;
  }

  // Step 3: Find duplicate rows based on "Product ID" column
  const dataRange = currentSheet.getUsedRange();
  const dataValues = dataRange.getValues();
  const duplicateGroups: { [key: string]: ExcelScript.Range[] } = {};

  for (let i = 1; i < dataValues.length; i++) {
    const productID = dataValues[i][productIDIndex - 1].toString().trim();
    if (productID !== "") {
      if (!duplicateGroups[productID]) {
        duplicateGroups[productID] = [currentSheet.getRangeByIndexes(i, 0, 1, currentSheet.getLastColumn())];
      } else {
        duplicateGroups[productID].push(currentSheet.getRangeByIndexes(i, 0, 1, currentSheet.getLastColumn()));
      }
    }
  }

  // Step 4: Loop through each group of matching duplicate rows
  for (const productID in duplicateGroups) {
    const rowRanges = duplicateGroups[productID];

    // Step 5: Find the first row with text in the specified columns in the given order
    let chosenRowRange: ExcelScript.Range | null = null;
    const locationColumnsOrder = [
      "Location 1",
      "Location 2",
      "Location 3",
      "Location 4",
      "Location 5",
      "Location 6",
      "Location 7",
    ];

    for (const rowRange of rowRanges) {
      for (const locationCol of locationColumnsOrder) {
        const colIndex = columnIndexes[locationCol];
        const cellValue = rowRange.getCell(0, colIndex - 1).getValue().toString().trim();
        if (cellValue !== "") {
          chosenRowRange = rowRange;
          break;
        }
      }

      if (chosenRowRange !== null) {
        break;
      }
    }

    // Step 6: If no text found, display a message and exit the script
    if (chosenRowRange === null) {
      const productIDValue = rowRanges[0].getCell(0, productIDIndex - 1).getValue().toString().trim();
      console.log(`Rows with Product ID '${productIDValue}' did not have a Location description.`);
      continue;
    }

    // Step 7: Copy cell values from specific columns of the chosen row to other rows in the group
    const chosenRowValues = chosenRowRange.getValues()[0];
    for (const rowRange of rowRanges) {
      if (!rowRange.getAddress().equals(chosenRowRange.getAddress())) {
        for (const colName of ["Attribute 1", "Attribute 2", "Attribute 3", "Attribute 4", "Attribute 5", "Attribute 6", "Attribute 7", "Attribute 8", "Attribute 9"]) {
          const colIndex = columnIndexes[colName];
          const cellValue = chosenRowValues[colIndex - 1];
          rowRange.getCell(0, colIndex - 1).setValue(cellValue);
        }
      }
    }
  }
}

字符串
Excel报告在此节中,类型Worksheet上不存在getLastColumn属性。我想我应该能够用headerRow.length替换currentSheet.getLastColumn(),如果它想要的只是列的总数的话。

// Step 3: Find duplicate rows based on "Product ID" column
  const dataRange = currentSheet.getUsedRange();
  const dataValues = dataRange.getValues();
  const duplicateGroups: { [key: string]: ExcelScript.Range[] } = {};

  for (let i = 1; i < dataValues.length; i++) {
    const productID = dataValues[i][productIDIndex - 1].toString().trim();
    if (productID !== "") {
      if (!duplicateGroups[productID]) {
        duplicateGroups[productID] = [currentSheet.getRangeByIndexes(i, 0, 1, currentSheet.getLastColumn())];
      } else {
        duplicateGroups[productID].push(currentSheet.getRangeByIndexes(i, 0, 1, currentSheet.getLastColumn()));
      }

步骤4中,无法推断变量const rowRanges = duplicateGroups[productID];的数据类型。

步骤7中,Excel显示if (!rowRange.getAddress().equals(chosenRowRange.getAddress())) {行中,.equals不存在于类型string上。我尝试用=替换它,但预期的语法是错误的。
另外,它还抱怨在循环中读取方法会导致性能下降,但我不认为这会阻止脚本工作。
如果你感兴趣,这是我给ChatGPT的声明:
编写一个Excel Office脚本,该脚本将查找当前工作表第1行中包含文本的所有单元格,并将文本与关联的列索引存储在一个数组中,以便列索引可以由脚本中稍后的文本说明引用。使用名为“产品ID”的列的索引,查找基于此列的工作表中的所有重复行。对于具有相同“产品ID”的每组重复行,循环遍历每行并按此特定顺序计算以下列(“位置1”或“位置2”)中的单元格值,以查找组中包含这些单元格之一中的文本的第一行。存储计算结果为true的行的范围。如果没有单元格值包含文本,请按顺序搜索以下列:“位置3”或“位置4”或“位置5”或“位置6”或“位置7”。存储计算结果为true的行的范围。如果没有单元格值包含文本,则从“产品ID”列复制单元格值,并在显示“没有位置描述”的消息中使用它,然后退出脚本。对于评估为true的行,从名为“属性1”和“属性2”和“属性3”和“属性4”和“属性5”和“属性6”和“属性7”和“属性8”和“属性9”的列中复制单元格值。将复制的值粘贴到组中具有相同“产品ID”的其他行的相同列位置的单元格中。注解脚本以解释脚本中每个步骤的作用。

1l5u6lss

1l5u6lss1#

AI生成的代码通常需要细化和调试。提供的代码示例是一个很好的起点,而不是一个完整的解决方案。
我的目标是遵循代码的整体逻辑和流程,但修复了错误以使其正常工作。

function main(workbook: ExcelScript.Workbook) {
    // Step 1: Find columns with text in row 1 and store the text with associated column index in an array
    const currentSheet = workbook.getActiveWorksheet();
    // Get values of row 1
    const headerRow = currentSheet.getUsedRange().getRow(0).getValues()[0];
    // getRange("1:1").getValues()[0]; 
    const columnIndexes: { [key: string]: number } = {};

    for (let i = 0; i < headerRow.length; i++) {
        const columnName = headerRow[i].toString().trim();
        if (columnName !== "") {
            columnIndexes[columnName] = i + 1; // Store the column index
        }
    }
    // console.log(columnIndexes)

    // Step 2: Find the index for the column called "Product ID"
    const productIDIndex = columnIndexes["Product ID"];
    if (!productIDIndex) {
        console.log("Column 'Product ID' not found.");
        return;
    }
    // console.log(productIDIndex);

    // Step 3: Find duplicate rows based on "Product ID" column
    const dataRange = currentSheet.getUsedRange();
    const dataValues = dataRange.getValues();
    const duplicateGroups: { [key: string]: ExcelScript.Range[] } = {};
    let lastCol = currentSheet.getUsedRange().getLastColumn().getColumnIndex() + 1;
    for (let i = 1; i < dataValues.length; i++) {
        const productID = dataValues[i][productIDIndex - 1].toString().trim();
        if (productID !== "") {
            if (!duplicateGroups[productID]) {
              duplicateGroups[productID] = [currentSheet.getRangeByIndexes(i, 0, 1, lastCol)];
            } else {
              duplicateGroups[productID].push(currentSheet.getRangeByIndexes(i, 0, 1, lastCol));
            }
        }
    }
    // console.log(duplicateGroups['1'][0].getAddress())

    // Step 4: Loop through each group of matching duplicate rows
    for (const productID in duplicateGroups) {
        const rowRanges = duplicateGroups[productID];

        // Step 5: Find the first row with text in the specified columns in the given order
        let chosenRowRange: ExcelScript.Range | null = null;
        const locationColumnsOrder = [
            "Location 1",
            "Location 2",
            "Location 3",
            "Location 4",
            "Location 5",
            "Location 6",
            "Location 7",
        ];

        for (const rowRange of rowRanges) {
            for (const locationCol of locationColumnsOrder) {
                const colIndex = columnIndexes[locationCol];
                const cellValue = rowRange.getCell(0, colIndex - 1).getValue().toString().trim();
                if (cellValue !== "") {
                    chosenRowRange = rowRange;
                    break;
                }
            }

            if (chosenRowRange !== null) {
                break;
            }
        }

        // Step 6: If no text found, display a message and exit the script
        if (chosenRowRange === null) {
            const productIDValue = rowRanges[0].getCell(0, productIDIndex - 1).getValue().toString().trim();
            console.log(`Rows with Product ID '${productIDValue}' did not have a Location description.`);
            continue;
        }

        // Step 7: Copy cell values from specific columns of the chosen row to other rows in the group
        const chosenRowValues = chosenRowRange.getValues()[0];
        for (const rowRange of rowRanges) {
            if (rowRange.getAddress() !== chosenRowRange.getAddress()) {
                for (const colName of ["Attribute 1", "Attribute 2", "Attribute 3", "Attribute 4", "Attribute 5", "Attribute 6", "Attribute 7", "Attribute 8", "Attribute 9"]) {
                    const colIndex = columnIndexes[colName];
                    const cellValue = chosenRowValues[colIndex - 1];
                    rowRange.getCell(0, colIndex - 1).setValue(cellValue);
                }
            }
        }
    }
}

字符串
x1c 0d1x的数据

更新

上一个代码示例严重依赖于对getCell的重复调用来从工作表中读取/写入数据。这可能成为性能瓶颈,尤其是在大型片材上。
下面是一个优化的版本,它通过数组来处理数据。通过预先将值加载到数组中并最小化逐个单元的访问,可以将操作向量化以提高效率。

function main(workbook: ExcelScript.Workbook) {
  // Step 1: Find columns with text in row 1 and store the text with associated column index in an array
  const currentSheet = workbook.getActiveWorksheet();
  // Get values of row 1
  const dataRange = currentSheet.getUsedRange();
  const headerRow = dataRange.getRow(0).getValues()[0];
  // getRange("1:1").getValues()[0]; 
  const columnIndexes: { [key: string]: number } = {};
  for (let i = 0; i < headerRow.length; i++) {
    const columnName = headerRow[i].toString().trim();
    if (columnName !== "") {
      columnIndexes[columnName] = i + 1; // Store the column index
    }
  }
  // Step 2: Find the index for the column called "Product ID"
  let productIDIndex = headerRow.indexOf("Product ID")
  if (productIDIndex === -1) {
    console.log("Column 'Product ID' not found.");
    return;
  }
  // console.log(productIDIndex, headerRow.length);
  // Step 3: Find duplicate rows based on "Product ID" column
  const dataValues = dataRange.getValues();
  const duplicateGroups: { [key: string]: String[] } = {};
  let lastCol = dataRange.getLastColumn().getColumnIndex() + 1;
  for (let i = 1; i < dataValues.length; i++) {
    const productID = dataValues[i][productIDIndex].toString().trim();
    if (productID !== "") {
      if (!duplicateGroups[productID]) {
        duplicateGroups[productID] = [i.toString()];
      } else {
        duplicateGroups[productID].push(i.toString());
      }
    }
  }
  // console.log(duplicateGroups['2'])
  // Step 4: Loop through each group of matching duplicate rows
  for (const productID in duplicateGroups) {
    const rowRanges = duplicateGroups[productID];
    // Step 5: Find the first row with text in the specified columns in the given order
    let chosenRowRange: ExcelScript.Range | null = null;
    const attList = ["Attribute 1", "Attribute 2", "Attribute 3",
      "Attribute 4", "Attribute 5", "Attribute 6",
      "Attribute 7", "Attribute 8", "Attribute 9"];
    const locationColumnsOrder = [
      "Location 1", "Location 2", "Location 3",
      "Location 4", "Location 5", "Location 6",
      "Location 7",
    ];
    // rewrite step 5
    const resultRow: { [key: string]: String } = {};
    for (let rowRange of rowRanges) {
      for (const locationCol of locationColumnsOrder) {
        // let locationCol = locationColumnsOrder[i]
        const colIndex = columnIndexes[locationCol] - 1;
        const cellValue = dataValues[parseInt(rowRange.toString())][colIndex];
        if (cellValue !== "") {
          // chosenRowRange = rowRange;
          resultRow[productID] = rowRange;
          // console.log(cellValue)
          console.log(Array(productID, rowRange, colIndex.toString()).join("-"))
          break;
        }
      }
      if (resultRow[productID]) { break; }
    }
    // Step 6: If no text found, display a message and exit the script
    if (resultRow[productID]) {
      // Step 7: Copy cell values from specific columns of the chosen row to other rows in the group
      for (const rowRange of rowRanges) {
        if (resultRow[productID] !== rowRange) {
          for (const colName of attList) {
            const colIndex = columnIndexes[colName] - 1;
            dataValues[parseInt(rowRange.toString())][colIndex] =
              dataValues[parseInt(resultRow[productID].toString())][colIndex]
          }
        }
      }
    }
    else {
      console.log(`Rows with Product ID '${productID}' did not have a Location description.`);
      continue;
    } // E6
  }
  // console.log(dataValues)
  dataRange.setValues(dataValues);
}

相关问题