将值从一个工作表粘贴到另一个工作表并删除重复项

时间:2015-11-17 18:03:15

标签: javascript google-apps-script google-sheets

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

输入数据通过Get Data函数进入importxml工作表。

但是,我想将Get Data工作表的所有值复制到Final Data工作表,如果有重复项(按行数),请附加唯一的行。

以下是我的尝试:

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

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

感谢您的回复!

1 个答案:

答案 0 :(得分:1)

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

要创建我们的密钥,我们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数组后,只需将其写入目标工作表即可。

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

  

范围宽度不正确,为6,但应为5(行?,文件“代码”)

填充行由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);
}