Формула / функция Google Spares для получения случайных значений без пересчета (randbetween) - PullRequest
0 голосов
/ 14 января 2019

Я пытаюсь добиться следующего. В Google Sparesheet у меня есть один лист со значениями «AllValues», на другом листе «Randomvalues» я хотел бы получить случайные значения из листа «AllValues».

Я попробовал два варианта, сначала я попробовал формулу randbetween:

=INDEX(AllValues!A4:A103,RANDBETWEEN(1,COUNTA(AllValues!A4:A103)),1)

Работает, но обновляет / пересчитывает новые значения все время, пока изменяется столбец. Много гуглил и кажется, что заморозить уже рассчитанные результаты не так уж и много.

Далее я попробовал функцию:

    function random() {
      var sss = SpreadsheetApp.getActiveSpreadsheet();
      var ss = sss.getSheetByName('Values'); //the sheet that has the data
      var range = ss.getRange(1,1,ss.getLastRow(), 4); //the range you need: 4 columns on all row which are available
      var data = range.getValues();

      for(var i = 0; i < data.length; i++) 
      { 
        var j = Math.floor(Math.random()*(data[i].length)); //method of randomization
        var element = data[i][j]; // The element which is randomizely choose
        ss.getRange(i+1, 6).setValue(element); 
      }
    }

Но эта функция у меня не работает, Google Sparesheet выдает ошибку в строке 11, что setVaue не разрешено.

Строка 11: ss.getRange(i+1, 6).setValue(element);

Гуглил и этот, есть много предложений, но я не очень знаком с функциями, мне не удалось заставить его работать.

Надеюсь, что кто-нибудь может мне помочь.

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

Использование формулы предполагает повторные вычисления обычно. Вы не можете предотвратить их и можете только попытаться вернуть старые значения. Эта задача не является тривиальной, поскольку любая формула не может ссылаться на ту же ячейку, где должен быть возвращен результат (происходит циклическая ссылка) Не используйте формулы для однократного расчета времени.

С другой стороны, использование функции скрипта позволяет генерировать необходимые данные напрямую и только один раз или по запросу. Я думаю, что функция ниже поможет вам понять все необходимые шаги для исходного и целевого диапазонов выборки.

function random() {
  var source = "AllValues!A4:A103",
      target = "RandomValues!F2:F22";
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sourceValues = ss.getRange(source).getValues(),
      targetRange = ss.getRange(target),
      targetValues = [];
  while (targetValues.length < targetRange.getHeight()) {
    var randomIndex = Math.floor(Math.random() * sourceValues.length);
    targetValues.push(sourceValues[randomIndex]);
  }
  targetRange.setValues(targetValues);
}

Вы можете запустить его вручную или выбрать подходящий триггер.

0 голосов
/ 05 февраля 2019

Есть несколько способов достижения этой цели.

Пользовательское меню

Как уже упоминалось @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)

Ссылки:

...