#javascript #google-apps-script #google-sheets #duplicates
#javascript #google-apps-script #google-sheets #дубликаты
Вопрос:
Я пытаюсь дедуплицировать весь свой лист, и скрипт работает нормально, однако для запуска требуется более 60 секунд. Я слишком усложняю это, и действительно ли есть более простой код, чтобы получить то, что мне нужно? Просто кажется, что для обработки такой простой задачи требуется много времени.
Мои данные находятся только между 4-12 тыс. строк.
function removeDuplicates() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[1];
var data = sheet.getDataRange().getValues();
var newData = [];
for (var i in data) {
var row = data[i];
var duplicate = false;
for (var j in newData) {
if (row.join() == newData[j].join()) {
duplicate = true;
}
}
//If not a duplicate, put in newData array
if (!duplicate) {
newData.push(row);
}
}
//Delete the old Sheet and insert the newData array
sheet.clearContents();
sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}
Ответ №1:
Если вы используете объект, вы значительно сократите количество итераций.
function removeDuplicates() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
const data = sheet.getDataRange().getValues();
let newDataObject = {};
for (let row of data) {
newDataObject[row.join()] = row;
}
const newData = Object.values(newDataObject);
// Clear the old Sheet and insert the newData array
sheet.clearContents();
sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}
Ответ №2:
В качестве другого подхода, как насчет использования метода removeDuplicates()
? Когда ваш скрипт модифицируется, он становится следующим.
Модифицированный скрипт:
function removeDuplicates() {
SpreadsheetApp.getActiveSpreadsheet().getSheets()[1].getDataRange().removeDuplicates();
}
Ссылка:
Ответ №3:
Теперь, когда у нас есть версия 8, вы можете использовать класс. Set
Не предпринимал никаких попыток сравнить производительность, поэтому я не знаю, будете ли вы справедливее, когда речь идет о скорости выполнения, хотя код гораздо более удобочитаем. Попробуйте следующее и расскажите мне, как это происходит:
// V8 runtime version using Set
function removeDuplicates(sheetName) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
var rows = sheet.getDataRange().getValues();
var dedupedValues = [];
var set = new Set();
rows.forEach(function(row) {
let key = row.join();
if (set.has(key)) return;
set.add(key);
dedupedValues.push(row);
});
//Delete the old Sheet and insert the dedupedValues array
sheet.clearContents();
sheet.getRange(1, 1, dedupedValues.length, dedupedValues[0].length).setValues(dedupedValues);
}
Если вам не нравится версия 8, вы можете сделать то же самое, используя решение @Diego…но с несколькими изменениями следующим образом:
// ES5 version using object keys
function removeDuplicates(sheetName) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
var rows = sheet.getDataRange().getValues();
var dedupedValues = [];
var keys = {};
rows.forEach(function(row) {
var key = row.join();
if (key in keys) return;
keys[key] = true;
dedupedValues.push(row);
});
//Delete the old Sheet and insert the dedupedValues array
sheet.clearContents();
sheet.getRange(1, 1, dedupedValues.length, dedupedValues[0].length).setValues(dedupedValues);
}
Комментарии:
1. Этот вопрос касается производительности, а не общего альтернативного кодирования. Например, простой цикл for быстрее, чем forEach .
2. Первое решение в вашем ответе очень полезно, если кто-то заинтересован в сравнении строк на основе результатов функции столбцов строк, потому что вы можете сохранить набор для сравнения и набор для конечного выходного массива, а затем повторно создать выходной массив с помощью оператора распространения. И тогда вам не нужно использовать
dedupedValues.push(row)
Вы можете просто использовать[...set]
Ответ №4:
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: я не знаю API Google Sheets.
Я предложил несколько улучшений и добавил комментарии в код. Большое значение в производительности имеет кэширование. Поэтому не делайте что-то дважды, если в этом нет необходимости (или DRY = Не повторяйтесь!). Если вы забыли свой кошелек и вам снова нужно подняться наверх, это удваивает время, затрачиваемое на то, чтобы покинуть парадную дверь. То же самое с кодом.
Если вы, как правило, заинтересованы в повышении производительности (и все должны быть) Я предлагаю вам взглянуть на то, как написать эффективный JavaScript — Марк Надаль
function removeDuplicates() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[1];
var data = sheet.getDataRange().getValues();
var newData = [];
var newDataJoinedCache = {};
// help the loop to not have to read the same values over and over again
// if you prepare as much data as possible for the loop it will thankfully speed up
for (var i = 0, len = data.length; i < len; i ) {
// data won’t change in the loop, so we can cache it here once(!)
// as you can see, I added a semicolon to prevent unwanted results
// imagine a row with colums [ "a", "bc"] and another one with [ "ab", "c"]
// just joined without separator they will both be the same "abc", which is wrong
var joinedRow = data[i].join(";");
// no need as we will know it with one simple comparison
// var duplicate = false;
// Just make one simple comparison
// instead of over and over joining the arrays in newData just cache them
if (!newDataJoinedCache[joinedRow]) {
newData.push(data[i]);
// we push the joined string as a cache
newDataJoinedCache[joinedRow] = true;
}
}
//Delete the old Sheet and insert the newData array
sheet.clearContents();
sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}
Дайте мне знать, как это работает и сколько времени это сэкономит в сравнении.
Комментарии:
1. Это заняло от 60 секунд в среднем до 10-15 секунд … некоторые были 3-4 секунды. Это потрясающе! Спасибо за ваше понимание!
2. Рад слышать 👍