javascript - 将值从一张纸粘贴到另一张纸并删除重复项

标签 javascript google-apps-script google-sheets

我的 Google 电子表格中有两个工作表:

输入数据通过 importxml 函数进入获取数据工作表。

但是,我想将获取数据工作表的所有值复制到最终数据工作表,如果有重复项(以行数计),则附加唯一的值行。

这是我尝试过的:

function onEdit() {
   //get the data from old Spreadsheet
 var ss = SpreadsheetApp.openById("1bm2ia--F2b0495iTJotp4Kv1QAW-wGUGDUROwM9B-D0");
 var dataRange = ss.getSheetByName("Get Data").getRange(1, 1, ss.getLastRow(), ss.getLastColumn());
 var dataRangeFinalData = ss.getSheetByName("Final Data").getRange(1, 1, ss.getLastRow(), ss.getLastColumn());
 var myData = dataRange.getValues();
 //Open new Spreadsheet & paste the data
newSS = SpreadsheetApp.openById("1bm2ia--F2b0495iTJotp4Kv1QAW-wGUGDUROwM9B-D0");
Logger.log(newSS.getLastRow());

newSS.getSheetByName("Final Data").getRange(newSS.getLastRow()+1, 1, ss.getLastRow(), ss.getLastColumn()).setValues(myData);
//remove duplicates in the new sheet
removeDups(dataRangeFinalData)
}

function getId() {
  Browser.msgBox('Spreadsheet key: ' + SpreadsheetApp.getActiveSpreadsheet().getId());
}

function removeDups(array) {
  var outArray = [];
  array.sort(lowerCase);
  function lowerCase(a,b){
    return a.toLowerCase()>b.toLowerCase() ? 1 : -1;// sort function that does not "see" letter case
  }
  outArray.push(array[0]);
  for(var n in array){
    Logger.log(outArray[outArray.length-1]+'  =  '+array[n]+' ?');
    if(outArray[outArray.length-1].toLowerCase()!=array[n].toLowerCase()){
      outArray.push(array[n]);
    }
  }
  return outArray;
}

您可以在下面找到示例电子表格的链接:

Sample Sheet

我的问题是数据没有被粘贴。

感谢您的回复!

最佳答案

tl;dr:请参阅底部的脚本。

onEdit()函数不适合您的用例,因为电子表格函数修改的单元格内容不被视为“编辑”事件。您可以阅读更多相关信息 in this answer 。如果您希望此操作自动化,那么定时触发功能将是合适的。或者,您可以通过菜单项手动调用该功能。我将把这个问题留给您来决定,因为您问题的真正核心是如何确保最终数据集中的行级唯一性。

合并唯一行

尽管您的原始代码不完整,但您似乎打算首先利用不区分大小写的字符串比较从源数据中删除重复项。我建议使用其他一些 JavaScript 魔法来代替。

我们对目标数据的唯一性感兴趣,因此我们需要一种方法将新行与已有的行进行比较。如果我们有字符串或数字数组,那么我们可以使用 How to merge two arrays in Javascript and de-duplicate items 中的技术。 。然而,这里有一个复杂的问题,因为我们有一个数组的数组,并且数组不能直接比较。

哈希

很好 - 我们仍然可以逐个元素地比较行,这需要对我们正在比较的行中的所有列进行简单的循环。简单,但速度慢,我们称之为 O(n2) solution (n 方阶)。随着要比较的行数增加,唯一比较操作的数量将呈指数增长。所以,我们不要这样做。

相反,我们将创建一个单独的数据结构来镜像我们的目标数据,但对于比较非常有效,即 hash .

在 JavaScript 中,我们可以通过对象的名称或键快速访问对象的属性。此外,该键可以是任何字符串。然后,我们可以创建一个简单的哈希表,其中包含一个对象,该对象的属性使用从目标数据行生成的字符串命名。例如,这将创建一个哈希对象,然后添加数组 row给它:

var destHash = {};
destHash[row.join('')] = true; // could be anything

要创建我们的 key ,我们是 join计算 row 中的所有值没有分隔符的数组。现在,为了测试行的唯一性,我们只需检查是否存在具有相同形式键的对象属性。像这样:

var alreadyExists = destHash.hasOwnProperty(row.join(''));

一个额外的考虑因素:由于源数据可能包含目标数据中尚未存在的重复行,因此我们需要在识别出唯一行时不断扩展哈希表。

过滤和连接

JavaScript 提供了两个内置数组方法,我们将使用它们 filter出已知行,并且 concatenate我们的目标数据只有唯一的行。

简单来说,它看起来像这样:

// Concatentate source rows to dest rows if they satisfy a uniqueness filter
var mergedData = destData.concat(sourceData.filter(function (row) {
  // Return true if given row is unique
}));

您可以将其理解为“创建一个名为 mergedData 的数组,该数组由名为 destData 的数组的当前内容组成,并将 sourceData 数组的过滤行连接到它。”

您会发现,由于已经提到的其他注意事项,最终的函数会稍微复杂一些。

更新电子表格

一旦我们有了mergedData数组,只需将其写入目标Sheet即可。

填充行:源数据包含宽度不一致的行,这在调用 setValues() 时会出现问题,它期望所有行都被平方。这将要求我们检查并填充行以避免此类错误:

Incorrect range width, was 6 but should be 5 (line ?, file "Code")

填充行由 push 完成在行数组末尾删除空白“单元格”,直到达到预期长度。

for (var col=mergedData[row].length; col<mergedWidth; col++)
  mergedData[row].push('');

处理完每一行后,我们终于准备好写出结果了。

最终脚本

function appendUniqueRows() {
  var ss = SpreadsheetApp.getActive();
  var sourceSheet = ss.getSheetByName('Get Data');
  var destSheet = ss.getSheetByName('Final Data');

  var sourceData = sourceSheet.getDataRange().getValues();
  var destData = destSheet.getDataRange().getValues();

  // Check whether destination sheet is empty
  if (destData.length === 1 && "" === destData[0].join('')) {
    // Empty, so ignore the phantom row
    destData = [];
  }

  // Generate hash for comparisons
  var destHash = {};
  destData.forEach(function(row) {
    destHash[row.join('')] = true; // could be anything
  });

  // Concatentate source rows to dest rows if they satisfy a uniqueness filter
  var mergedData = destData.concat(sourceData.filter(function (row) {
    var hashedRow = row.join('');
    if (!destHash.hasOwnProperty(hashedRow)) {
      // This row is unique
      destHash[hashedRow] = true;   // Add to hash for future comparisons
      return true;                  // filter -> true
    }
    return false;                   // not unique, filter -> false
  }));

  // Check whether two data sets were the same width
  var sourceWidth = (sourceData.length > 0) ? sourceData[0].length : 0;
  var destWidth = (destData.length > 0) ? destData[0].length : 0;
  if (sourceWidth !== destWidth) {
    // Pad out all columns for the new row
    var mergedWidth = Math.max(sourceWidth,destWidth);
    for (var row=0; row<mergedData.length; row++) {
      for (var col=mergedData[row].length; col<mergedWidth; col++)
        mergedData[row].push('');
    }
  }

  // Write merged data to destination sheet
  destSheet.getRange(1, 1, mergedData.length, mergedData[0].length)
           .setValues(mergedData);
}

关于javascript - 将值从一张纸粘贴到另一张纸并删除重复项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33763928/

相关文章:

javascript - Google 脚本 - 将 Gmail 附件添加到云端硬盘中的文档和流程

REGEXEXTRACT 与捕获组

google-apps-script - onOpen() 函数在桌面上触发,但在 Android 上不触发

javascript - Bootstrap 轮播一次显示所有幻灯片

javascript - 我需要一个 JQuery IP Mask 插件

javascript - 如何停止在特定按钮上生成代码?

javascript - Google 脚本 onChange 第三方 INSERT_ROW

javascript - 比较标题字段和数组时避免错误

javascript - 谷歌应用脚​​本: Number of days between two dates after subtracting full months

javascript - Google App Script - 在 2 个 SpreadSheets 之间导入所有范围格式