Это продолжение вопроса, который я задал некоторое время назад. Человек, который ответил на него, попросил меня создать новый вопрос, а не изменять существующий, и вот он.
Вот образец документа. В этом документе всего 5 вкладок:
Вот что у меня есть на данный момент:
// This is from your provided Spreadsheet.
const obj = [
{ name: "Dataset Before", range: "A2:A" },
{ name: "Completion Data", range: "A2:C" },
{ name: "Settings", range: "E5:I" }
];
// 1. Retrieve values and ranges from 3 sheets.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const [sheet1, sheet2, sheet3] = obj.map(({ name, range }, i) => {
obj[i].sheet = ss.getSheetByName(name);
obj[i].range = obj[i].sheet.getRange(range + obj[i].sheet.getLastRow());
obj[i].values = obj[i].range.getValues();
if (i == 1) {
// For "Completion Data" sheet.
// Create an object for searching values.
obj[i].values = obj[i].values.reduce((o, [a, b, c]) => {
if (c == "Completed") {
o[b] = o[b] ? { ...o[b], [a]: c } : { [a]: c };
}
return o;
}, {});
} else if (i == 2) {
// For "Settings" sheet.
// Transpose the retrieved values.
obj[i].len = obj[i].values[0].length;
obj[i].values = obj[i].values[0].map((_, col) => obj[i].values.map((row) => row[col]));
}
return obj[i];
});
// Create an array for putting into the destination range by follwoing your logic.
const values = sheet1.values.map(([a]) => {
if (sheet2.values[a]) {
return sheet3.values.map(e => e.some(f => sheet2.values[a][f]) ? "Completed" : "Incomplete");
}
return Array(sheet3.len).fill("Incomplete");
});
// Put the values to the destination range.
sheet1.sheet.getRange(2, 2, values.length, values[0].length).setValues(values);
}
В настоящее время сценарий делает то, что я хочу, и делает это примерно за 40 секунд. Действительно быстро по сравнению с тем, что у меня было раньше. Он ищет идентификатор человека на вкладке «Данные о завершении» и возвращает «Завершено», если в статусе указано «Завершено», или «Незавершено», если возвращается какой-либо другой статус.
Новое требование:
Теперь мне нужно, чтобы он вернул дату завершения, объединенную со словом «Завершено», например Completed (04/24/2024)
, или вернул Incomplete (Enrolled)
, если статус показывает «Зарегистрирован», в противном случае просто Incomplete
.
К сожалению, я не до конца понимаю, что происходит в этом сценарии, чтобы внести нужные мне изменения. Я пытался создать что-то с нуля самостоятельно, используя имеющиеся знания, но это включало циклы внутри циклов и занимало более 15 минут на каждый столбец. Время выполнения не позволило бы всему этому закончиться.
При попытке изменить приведенный выше код я предположил, что нужно внести изменения в return sheet3.values.map(e => e.some(f => sheet2.values[a][f]) ? "Completed" : "Incomplete");
, но я продолжал получать ошибки. На данный момент это слишком сложно для меня, и я был бы очень признателен за помощь.
Пожалуйста, дайте мне знать, если я что-то упустил или что-то неясно, чтобы я мог отредактировать свое сообщение. Спасибо.
Около @Tanaike Tagging person who suggested I create a new question.
на листе «Результат набора данных (новое требование)» в столбцах от «C» до «E» указано только «Неполный». Могу ли я спросить вас о причине этого? Во-первых, мне хотелось бы правильно понять Ваш вопрос.
Я только что убедился, что это правда. В столбцах C–E указано «Незавершено», поскольку у этих курсов нет статуса. Если в статусе указано «Завершено», должно быть указано «Завершено (мм/дд/гггг)». Если в статусе указано «Зарегистрировано», должно быть написано «Незавершено (Зарегистрировано)». Все остальное или недостающее должно быть отмечено как «Не завершено».
Я добавил еще несколько строк для примеров.
Спасибо за ответ. Когда я увидел обновленную таблицу, я не мог понять, почему 6878682316
есть Completed (08/15/2023),Completed (08/13/2023),Incomplete,Incomplete (Enrolled),Completed (08/24/2023)
. Я догадалась, что это может быть Incomplete,Incomplete,Incomplete,Incomplete,Incomplete
. Могу ли я спросить вас о деталях? Кстати, ваша просьба в этом вопросе - добиться только «Результат набора данных (новое требование)» из листов «Набор данных до», «Данные завершения» и «Настройки»? Во-первых, мне хотелось бы правильно понять Ваш вопрос. Я прошу прощения за эту ситуацию.
Каждый идентификатор может иметь одну запись для каждого курса. Если вы отфильтруете номер 6878682316 на вкладке «Данные о завершении», вы увидите, что у них есть статус для каждого курса. Я обновил «Данные о завершении», чтобы это соответствовало этому идентификатору. Если вы скопировали его ранее, замените его новыми данными. Что касается второго вопроса, вы правы... «Результат набора данных (новое требование)» — это то, чего я пытаюсь достичь с помощью других вкладок, которые вы упомянули. И не надо извиняться. Ты обалденный. Спасибо, что изучили это.
Спасибо за ответ. Что касается If you filter for 6878682316 on "Completion Data" tab you will see that they have a status for each course. I updated the "Completion Data" so that would be the case for this ID.
, когда я проверил 6878682316
на листе «Данные о завершении», никаких значений обнаружено не было. Я обеспокоен тем, что ваша ситуация может отличаться от предоставленной вами таблицы. Но я хотел бы это подтвердить. Когда я повторяю это, мне хотелось бы подумать о решении.
Я понимаю. Мои извинения. Я присвоил этот статус не тому человеку. Ты прав. Все должно быть незавершенным. Я только что внес изменения, чтобы этот идентификатор соответствовал сценарию, который я собирался использовать. Пожалуйста, скопируйте вкладку данных завершения еще раз.
@Танаике не уверен, что ты видел мой ответ, но надеюсь, что теперь ты понимаешь. Дайте мне знать, если у вас есть еще вопросы.
Спасибо за ответ. Из вашего ответа я предложил модифицированный сценарий. Пожалуйста, подтвердите это.
В вашей ситуации, в качестве простой модификации, как насчет следующей модификации?
function myFunction() {
// This is from your provided Spreadsheet.
const obj = [
{ name: "Dataset Before", range: "A2:A" },
{ name: "Completion Data", range: "A2:D" },
{ name: "Settings", range: "E5:I" }
];
// 1. Retrieve values and ranges from 3 sheets.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const [sheet1, sheet2, sheet3] = obj.map(({ name, range }, i) => {
obj[i].sheet = ss.getSheetByName(name);
obj[i].range = obj[i].sheet.getRange(range + obj[i].sheet.getLastRow());
obj[i].values = obj[i].range.getDisplayValues();
if (i == 1) {
// For "Completion Data" sheet.
// Create an object for searching values.
obj[i].values = obj[i].values.reduce((o, [a, b, c, d]) => {
if (c == "Completed") {
o[b] = o[b] ? { ...o[b], [a]: `${c} (${d})` } : { [a]: `${c} (${d})` };
} else if (c == "Enrolled") {
o[b] = o[b] ? { ...o[b], [a]: `Incomplete (${c})` } : { [a]: `Incomplete (${c})` };
}
return o;
}, {});
} else if (i == 2) {
// For "Settings" sheet.
// Transpose the retrieved values.
obj[i].len = obj[i].values[0].length;
obj[i].values = obj[i].values[0].map((_, col) => obj[i].values.map((row) => row[col]));
}
return obj[i];
});
// Create an array for putting into the destination range by following your logic.
const values = sheet1.values.map(([a]) => {
if (sheet2.values[a]) {
return sheet3.values.map(e => {
const k = e.find(f => sheet2.values[a][f])
return k ? sheet2.values[a][k] : "Incomplete";
});
}
return Array(sheet3.len).fill("Incomplete");
});
// Put the values to the destination range.
sheet1.sheet.getRange(2, 2, values.length, values[0].length).setValues(values);
}
Когда этот сценарий запускается в предоставленной вами электронной таблице, на листе «Набор данных до» получается следующий результат.
Судя по вашему следующему ответу,
Это увеличило время обработки примерно на 20 секунд (~ 70 000 строк в наборе данных, ~ 150 000 в данных завершения) в общей сложности на 1 минуту 10 секунд... но это не имеет большого значения.
В качестве простой модификации, как насчет замены getValues
и serValues
на Sheets API следующим образом?
Прежде чем использовать этот скрипт, включите Sheets API в расширенных сервисах Google.
function myFunction() {
// This is from your provided Spreadsheet.
const obj = [
{ name: "Dataset Before", range: "A2:A" },
{ name: "Completion Data", range: "A2:D" },
{ name: "Settings", range: "E5:I" }
];
// 1. Retrieve values and ranges from 3 sheets.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ssId = ss.getId();
const [sheet1, sheet2, sheet3] = obj.map(({ name, range }, i) => {
obj[i].sheet = ss.getSheetByName(name);
obj[i].range = obj[i].sheet.getRange(range + obj[i].sheet.getLastRow());
// obj[i].values = obj[i].range.getDisplayValues();
obj[i].values = Sheets.Spreadsheets.Values.get(ssId, `'${name}'!${range}`, { valueRenderOption: "FORMATTED_VALUE" }).values;
if (i == 1) {
// For "Completion Data" sheet.
// Create an object for searching values.
obj[i].values = obj[i].values.reduce((o, [a, b, c, d]) => {
if (c == "Completed") {
o[b] = o[b] ? { ...o[b], [a]: `${c} (${d})` } : { [a]: `${c} (${d})` };
} else if (c == "Enrolled") {
o[b] = o[b] ? { ...o[b], [a]: `Incomplete (${c})` } : { [a]: `Incomplete (${c})` };
}
return o;
}, {});
} else if (i == 2) {
// For "Settings" sheet.
// Transpose the retrieved values.
obj[i].len = obj[i].values[0].length;
obj[i].values = obj[i].values[0].map((_, col) => obj[i].values.map((row) => row[col]));
}
return obj[i];
});
// Create an array for putting into the destination range by follwoing your logic.
const values = sheet1.values.map(([a]) => {
if (sheet2.values[a]) {
return sheet3.values.map(e => {
const k = e.find(f => sheet2.values[a][f])
return k ? sheet2.values[a][k] : "Incomplete";
});
}
return Array(sheet3.len).fill("Incomplete");
});
// console.info(values)
// Put the values to the destination range.
// sheet1.sheet.getRange(2, 2, values.length, values[0].length).setValues(values);
Sheets.Spreadsheets.Values.update({ values }, ssId, `'${sheet1.name}'!B2`, { valueInputOption: "USER_ENTERED" });
}
Это сделало это. Это увеличило время обработки примерно на 20 секунд (~ 70 000 строк в наборе данных, ~ 150 000 в данных завершения) в общей сложности на 1 минуту 10 секунд... но это не имеет большого значения. Определенно стоит потраченного времени по сравнению с альтернативным решением, которое у меня было. Спасибо!
@DanCue Спасибо за ответ. Из вашего ответа я добавил еще один скрипт. Пожалуйста, проверьте это еще раз. Я думаю, что в этом случае стоимость процесса можно будет немного снизить.
Ты быстрый. Я почти сразу удалил свой комментарий, потому что понял это. Да, я заменил ваш values
на shtValues
.
Отличный! Это сократило время вдвое. Довольно круто, спасибо!
На самом деле это лучше, чем я думал. 13 секунд. Я понял, что все еще вызываю полный набор данных с помощью getValues
в другой строке, которую использовал для старого сценария. Избавился от этого, и эта штука работает молниеносно.
@Tanaike Отмечаю человека, который предложил мне создать новый вопрос.