2

我正在使用一个脚本,它从日历中提取事件详细信息并将它们添加到电子表格的 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);

}
4

2 回答 2

3

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

您的第一列由Date对象组成,只有当比较的双方都是相同的 object==时,比较器才会评估这些对象。在整行比较中,日期被操作强制转换为字符串。我们可以逐个单元地获得相同的效果,如下所示: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);
}
于 2013-03-20T16:12:19.750 回答
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]) }
  }
于 2013-03-20T16:13:30.190 回答