Есть несколько способов достижения этой цели.
Пользовательское меню
Как уже упоминалось @Tanaike, вы можете избежать пересчета и зависимости формулы, используя пользовательское меню:
// @OnlyCurrentDoc
// Create a function that binds the "simple trigger" for the open event:
function onOpen(e) {
// Add a menu to the UI with the function we want to be able to invoke.
const ui = SpreadsheetApp.getUi();
ui.createMenu("Randomizer")
.addItem("Sample from 'AllValues' sheet", "sampleAllValues")
.addToUi();
}
Затем вам нужно определение функции, соответствующее этому имени sampleAllValues
, и когда пользователь выбирает соответствующий параметр меню, он будет вызываться с разрешениями щелкающего пользователя (пользователю сначала будет предложено дать согласие на доступ к области действия сценария OAuth).
function sampleAllValues() {
const wb = SpreadsheetApp.getActive();
const destination = wb.getSheetByName("RandomValues");
const source = wb.getSheetByName("AllValues");
if (!source || !destination)
throw new Error("Missing required sheets 'RandomValues' and 'AllValues'");
// Create a flat array of all non-empty values in all rows and columns of the source sheet.
const data = source.getDataRange().getValues().reduce(function (compiled, row) {
var vals = row.filter(function (val) { return val !== ""; });
if (vals.length)
Array.prototype.push.apply(compiled, vals);
return compiled;
}, []);
// Sample the smaller of 50 elements or 10% of the data, without replacement.
const sample = [];
var sampleSize = Math.min(50, Math.floor(data.length * .1));
while (sampleSize-- > 0)
{
var choice = Math.floor(Math.random() * data.length);
Array.prototype.push.apply(sample, data.splice(choice, 1));
}
// If we have any samples collected, write them to the destination sheet.
if (sample.length)
{
destination.getDataRange().clearContent();
// Write a 2D column array.
destination.getRange(1, 1, sample.length, 1)
.setValues(sample.map(function (element) { return [ element ]; }));
// Write a 2D row array
// destination.getRange(1, 1, 1, sample.length)
// .setValues( [sample] );
}
}
Пользовательская функция
Если вы все еще хотите использовать пользовательскую функцию из листа RandomValues
, например,
RandomValues!A1: =sampleAllValues(50, AllValues!A1:A)
тогда вам нужно будет return sample
вместо записи на конкретный лист. Обратите внимание, что пользовательские функции обрабатываются детерминистически - они вычисляются во время ввода и затем пересчитываются только при изменении значений их аргументов. Пользовательские функции работают с очень ограниченной областью действия, поэтому обязательно ознакомьтесь с их ограничениями.
Приведенное выше использование указывает на то, что может оказаться полезным разрешить передачу количества требуемых выборок и значений для выборки:
function sampleAllValues(sampleSize, value2Darray) {
const data = value2Darray.reduce(function (compiled, row) {
/* as above */
}, []);
/* sample as above */
return sample; // Must be 2D row or 2D column array, or a single primitive e.g. `1`
}
Независимо от того, какой маршрут вы выберете, обязательно просмотрите журнал ошибок вашего скрипта, просмотрев журналы Stackdriver вашего скрипта. (Просмотр -> Ведение журнала Stackdriver)
Ссылки: