Добавлять только уникальные строки - PullRequest
1 голос
/ 03 февраля 2020

У меня проблемы с созданием скрипта, который бы добавлял только строки, которых в данный момент нет на листе.

У меня есть мастер-лист, в который я импортирую csvData. На данный момент у меня есть 1 скрипт для импорта данных в формате csv и другой для очистки листа от возможных дубликатов после импорта. Хотя это работает, скрипт удаления дубликатов использует .clearContent и вынужден полностью очистить лист перед возвратом списка уникальных строк. Поскольку электронная таблица используется извне (с помощью приложения), она создает риск незаписанных / поврежденных данных, если кто-либо из пользователей попытается добавить что-либо на лист во время выполнения сценария.

Из-за этого Я пытаюсь создать другой сценарий, который импортирует csvData в пустой массив, а затем сравнивает его с массивом, извлеченным из мастер-листа. При сравнении сценарий будет добавлять только те строки, которые еще не представлены на мастер-листе.

К сожалению, я не смог найти примеры удаления дубликатов без очистки содержимого листа. У меня была другая идея для подсчета повторений и выбора только тех, у которых их не было, но я также не смог сделать работающий сценарий / найти пример для этого.

Ниже приведен мой оригинальный скрипт, который включает в себя как импорт, так и удаление дубликатов с использованием .clearContent:

function importEMS() {
  var fSource=DriveApp.getFolderById('folder id removed'); 
  var fi=fSource.getFilesByName('EMS.csv'); 
  var ss=SpreadsheetApp.openById('sheet id removed');

  //CONVERT CSV FILE TO A TABLE
  if (fi.hasNext()) { 
    var file=fi.next();
    var csv=file.getBlob().getDataAsString();
    var csvData=CSVToArray(csv);
    var timestamp = new Date();
    var tsh=ss.getSheetByName('Main');
    for (var i=1;i<csvData.length-1;i++) {
      csvData[i][8] = timestamp;
    }

   //APPEND NEW ROWS

    for (var i=1;i<csvData.length;i++) {
      tsh.appendRow(csvData[i]);
    }
  }

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("Main");
  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,7).join().toLowerCase() == newData[j].slice(0,7).join().toLowerCase()){
        duplicate = true;
      }
    }
    if(!duplicate){
      newData.push(row);
    }
  }
  // Clear the existing info and update with newData.
  sheet.clearContents();
  sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}

Кто-нибудь имеет представление о том, как добавлять новые строки только вместо целых csvData к основному листу?

Спасибо за помощь заранее!

UPD: добавлена ​​ссылка к образцу данных. Реальный основной лист содержит 20 столбцов, но я удалил их из образца, порядок столбцов идентичен. Лист импорта CSV - это тип данных, которые я импортирую. На этом листе я выделил зеленым, какие строки я пытаюсь добавить на основной лист.

UPD2: предоставляется решением от функций Олега Вальтера, но только если я заменю .getValues() на .getDisplayValues(), который преобразует все существующие типы данных в строки, что также является форматом, в котором импортируются данные .csv ,

1 Ответ

2 голосов
/ 03 февраля 2020

Решение

  1. Получите значения CSV в виде массива массивов (предположим, что это CSVToArray()).
  2. Получите текущие значения в виде массива массивов через getDataRange().getValues().
  3. Отфильтруйте повторяющиеся значения, как это (при условии, что каждая пара строк имеет одинаковую длину - в противном случае алгоритм становится более сложным, но, судя по вашему коду, Вы проверяете только первые 8 значений):

//source = [[...], ... , [...]];
//target = [[...], ... , [...]];

/**
 * Checks if at least one element
 * is positioned differently
 * @param {*[]} a
 * @param {*[][]} b
 * @returns {Boolean}
 */
var unique = function (a,b) {
  return b.every(function(bRow){
    return a.some(function(A,aIdx){
      return A !== bRow[aIdx];
    });
  });
};

/**
 * Leaves only values not present in source
 * @param {*[][]} source
 * @param {*[][]} target
 * @returns {*[][]}
 */
var filterUnique = function (source,target) {
  return target.filter(function (row) {
    return unique(row,source);
  });
};

var S1 = [[1,2,3],['A','D','C'],[5],[7]];
var T1 = [[1,2,3],['A','B','C'],[6]];

var S2 = [[1.00,'Vehicle 1',1.00,'Ready','12-5-2020',	1, 'Event A',	'Location A']];
var T2 = [S2[0],[2.00,'V2',1.00,'Ready','12-5-2020', 1, 'Event A', 'Location A']];

var check1 = filterUnique(S1,T1);
var check2 = filterUnique(S2,T2);

console.log(check1,check2);

Примечания

  1. Вам нужно будет поменять чек с отметкой времени и только отметкой времени, оставив только уникальные строки, в противном случае существует риск добавления строки, поскольку ее временная метка является единственной разницей.

Ссылки

  1. every() метод ref по MDN
  2. some() метод ref по MDN
  3. filter() метод ref по MDN
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...