Google Script可根据2列标准删除重复行

时间:2013-03-20 13:21:30

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

我正在使用一个脚本来从日历中提取事件详细信息,并将它们添加到电子表格中的A列和B列中,删除所有重复的事件,然后根据日期进行排序。我希望我可以让工作人员在C,D等列中添加有关这些事件的其他数据。

这似乎工作正常,但是一旦在C,D列中添加了信息,脚本重复数据删除功能就会停止工作,因为它正在比较整行,而不仅仅是正在导入的内容。

是否有一种方法可以调整以下重复数据删除脚本,以便在判断行是否重复且应该删除时仅检查A列和B列?

我试图使用下面的代码(目前已注释掉)调整,如本文的变体部分所示:https://developers.google.com/apps-script/articles/removing_duplicates - 但它似乎仍无效。

感谢您的帮助

剧本:

enter code here

//this section retrieves the information from a calendar from a user submitted date until the end of the year

function importEvents(){
  var calID = Browser.inputBox("Please enter your google Cal ID", Browser.Buttons.OK_CANCEL);
  var startdate = Browser.inputBox("Start date using 1/1/2013 format", Browser.Buttons.OK_CANCEL);
  var cal = CalendarApp.getCalendarById(calID);
  var events_sheet = SpreadsheetApp.getActiveSheet();
  var events = cal.getEvents(new Date(startdate), new Date("1/1/2014"));
  var lr = events_sheet.getLastRow();
  var eventarray = new Array();

  var i = 0; // edited
    for (i = 0; i < events.length; i++) {
      line = new Array();
      line.push(events[i].getStartTime());
      line.push(events[i].getTitle());

     //Potential more data that I am not getting at this time
     // line.push(events[i].getDescription());
     // line.push(events[i].getEndTime());

      eventarray.push(line);
    }

    events_sheet.getRange("A"+(lr+1)+":B"+(lr+i)).setValues(eventarray);

  //sort ascending dy date

  var range = SpreadsheetApp.getActiveSheet().getRange("A3:F2000"); 
  range.sort([{column: 1, ascending: true}]); 

  //removes duplicate rows

  var sheet = SpreadsheetApp.getActiveSheet();
  var data = sheet.getDataRange().getValues();
  var newData = new Array();
  for(i in data){
    var row = data[i];
    var duplicate = false;
    for(j in newData){

      if(row.join() == newData[j].join()){
  duplicate = true;

   //This was supposed to only check the first 2 columns, but it doesn't work
   //I found this code in the variation section of this tutorial: https://developers.google.com/apps-script/articles/removing_duplicates   
   //     
   //  if(row[0] == newData[j][0] && row[1] == newData[j][1]){
   // duplicate = true;

      }
    }
    if(!duplicate){
      newData.push(row);
    }
  }
  sheet.clearContents();
  sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);

}

2 个答案:

答案 0 :(得分:3)

通过一些调整,可以使注释掉的块可以工作。由于数据的性质以及教程没有考虑对象比较的工作方式,因此出现了问题。 (请参阅JavaScript Date Object Comparison。)

您的第一列包含Date个对象,只有当比较的两边都是同一个对象时,==比较器才会评估true。在整行比较中,.join()操作将日期强制转换为字符串。我们可以逐个细胞地获得相同的效果,如下所示:

 if(row[0].toString() == newData[j][0].toString() && row[1] == newData[j][1]){
   duplicate = true;
 }

或者,我们可以使用Array.slice()操作将比较限制为前两列。这样,我们不需要知道要比较的类型,因为我们仍然会使用.join()来形成一个字符串进行比较:

if(row.slice(0,2).join() == newData[j].slice(0,2).join()){
  duplicate = true;
}

排序

您将遇到的另一个问题是range.sort()的展示位置。在删除重复项之前进行排序是危险的,因为您无法保证新检索的事件数据的顺序与您已经拥有的可能具有其他信息列的同一事件的数据。因此,重复删除可能会删除用户输入的信息。将排序作为最后一步更安全,或者在排序中包含其他列以保证顺序。

另一个小问题:使用.getRange("A3:F2000")会产生将电子表格扩展到2000行的副作用;你可以使用.getRange("A3:F"),它将检索最大范围而不扩展它。

但我建议你完全使用javascript数组进行排序,这比使用电子表格服务要快得多。我假设你有两行标题信息要保留在表格的顶部,因为你是从A3排序的。这是一种进行排序的方法:

// sort ascending by date - retain header lines
var headers = newData.slice(0,2);
var sorted = newData.slice(2).sort(sortFunction);
var newData = headers.concat(sorted);

sortFunction()的位置:

function sortFunction( a, b ) {
  // coerce dates to numbers and return comparison
  return ((+a[0]) - (+b[0]))
}

最终剧本

通过以上更改,这就是你得到的。

function importEvents(){
  var calID = Browser.inputBox("Please enter your google Cal ID", Browser.Buttons.OK_CANCEL);
  var startdate = Browser.inputBox("Start date using 1/1/2013 format", Browser.Buttons.OK_CANCEL);
  var cal = CalendarApp.getCalendarById(calID);
  var events_sheet = SpreadsheetApp.getActiveSheet();
  var events = cal.getEvents(new Date(startdate), new Date("1/1/2014"));
  var lr = events_sheet.getLastRow();
  var eventarray = new Array();

  var i = 0; // edited
  for (i = 0; i < events.length; i++) {
    line = new Array();
    line.push(events[i].getStartTime());
    line.push(events[i].getTitle());

     //Potential more data that I am not getting at this time
     // line.push(events[i].getDescription());
     // line.push(events[i].getEndTime());

    eventarray.push(line);
  }

  // Append the retreived events to existing spreadsheet
  events_sheet.getRange("A"+(lr+1)+":B"+(lr+i)).setValues(eventarray);

  //remove duplicate rows
  var sheet = SpreadsheetApp.getActiveSheet();
  var data = sheet.getDataRange().getValues();
  var newData = new Array();
  for(i in data){
    var row = data[i];
    var duplicate = false;
    for(j in newData){

      if(row.slice(0,2).join() == newData[j].slice(0,2).join()){
        duplicate = true;
      }
    }
    if(!duplicate){
      newData.push(row);
    }
  }

  // sortFunction used to compare rows of data in our newData array
  function sortFunction( a, b ) {
    // coerce dates to numbers and return comparison
    return ((+a[0]) - (+b[0]))
  }

  // sort ascending by date - retain header lines
  var headers = newData.slice(0,2);
  var sorted = newData.slice(2).sort(sortFunction);
  var newData = headers.concat(sorted);

  // Clear the existing info and update with newData.
  sheet.clearContents();
  sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}

答案 1 :(得分:0)

我建议你一直保持阵列级别,包括排序过程。

您可以使用下面的排序功能轻松选择您排序的单元格:

// This example sorts on first column of data array
  data.sort(function(x,y){
  var xp = x[0];
  var yp = y[0];
  //Logger.log(xp+'   '+yp);// just to check that it takes the right column
  return xp == yp ? 0 : xp < yp ? -1 : 1;// first sort  ascending
});

对于重复删除,有几种方法可以做到,一种可能是这样的:

var newData = new Array();
  for(var i in data){
    var duplicate = false;
    for(var j in newData){

      if(data[i][0].toString()+data[i].toString() == newData[j][0].toString()+newData[j][1].toString()){ duplicate = true }
    }
    if(!duplicate){ newData.push(data[i]) }
  }