Google Active Script: использование карты в массиве с 2 аргументами - PullRequest
0 голосов
/ 24 сентября 2019

Это работает:

Предположим, я хочу использовать в ArrayFormula() функцию indirect(), которая не работает.То есть, если я наберу это в ячейке E1, =ArrayFormula(indirect(address(row(E:E),column(A:A)))), это вернет значение ячейки A1 во всех ячейках в column E.Чтобы обойти это, я создал пользовательскую функцию ниже:

function retValue(cell){
  if(cell.map) {
    return cell.map(retValue);
  } else {
    var cellRang = SpreadsheetApp.getActive().getRange(cell);
    return cellRang.getValue();
  }
}

Теперь, когда я введу этот =ArrayFormula(retValue(address(row(E:E),column(A:A)))) в ячейку E1, каждая ячейка в column E будет иметь соответствующее значение ячейки вта же строка column A.

Моя проблема:

Мне нужно иметь пользовательскую функцию, которая получает 2 аргумента, например function retValue2(cell, anotherRange), но я тольковсе равно, если cell это массив, так как anotherRange должен быть массивом в любом случае.Что происходит, когда я итеративно вызываю cell.map(retValue2), аргумент anotherRange теряется, и я не совсем уверен, как это сделать.

Я пытался придумать это:

function retValue2(cell, anotherRange) {
  if (cell.map) {
    return cell.map(retValue2);
  } else {
    var range = SpreadsheetApp.getActive().getRange(anotherRange);
    var nrRows = range.getNumRows();
    var nrCols = range.getNumColumns();
    return cell + ',' + nrRows + ',' + nrCols;
  }
}

Но он терпит неудачу, потому что anotherRange не распознается внутри итерации, я думаю.Как мне решить эту проблему?

PS .: в примере, который работает, почему он вообще работает?Я понимаю, что когда я делаю это return cell.map(retValue);, он будет использовать мою собственную функцию в качестве обратного вызова, которая будет возвращать все значения в массиве, но в электронной таблице он показывает только одно значение в той же строке.В чем здесь магия?

РЕДАКТИРОВАТЬ:

Моя конечная цель - создать собственную функцию поиска, в которой я передаю ключ поиска и двумерный массив (строкии столбцы), а затем он находит координаты этого ключа в массиве.

Посмотрите здесь:

function retCoord(sKey, sIRange) {
  try {
    var key = SpreadsheetApp.getActive().getRange(sKey).getValue();
  }
  catch(e) {
    var key = sKey;
  }
  var range = SpreadsheetApp.getActive().getRange(sIRange).getValues();
  nbRow = range.length;
  nbColumn = range[0].length;
  for(var i = 0; i<nbRow; i++){
    for(var j = 0; j<nbColumn; j++){
      if(range[i][j] == key){
        return i + ", " + j;
      }
    }
  }
}

Если в моей электронной таблице я введу что-то вроде =retCoord("K4","A:L"), он будет искатьсодержимое ячейки K4 в моем 2-мерном массиве A: L и возвращаемое значение в массиве, например 1, 2.Это также работает, если я использую =retCoord(K4,"A:L") или =retCoord("term searched","A:L"), и в этом последнем случае я непосредственно ввожу искомый термин.Это работает нормально, пока я не использую его в ArrayFormula().

Во-первых, вместо =retCoord("K4","A:L") я мог бы очень хорошо использовать, например, =retCoord(address(4, 11),"A:L"), и мой метод .getRange() мог бы получить ячейку K4 простохорошо.

Теперь вот большая проблема.Я хочу использовать свою функцию в ArrayFormula() и, поместив курсор в O1 и надеясь найти элементы от column D в columns E до L, которые я хочу передать как один из входовaddress(), row(O:O), например: =ArrayFormula(retCoord(address(row(O:O),4,4),"E:L")), что означает, что для каждой строки передается новый адрес.то есть в ячейке O1 должен возвращаться результат retCoord(D1,"E:L"), в O2 должно быть retCoord(D2,"E:L"), в O3 должно быть retCoord(D3,"E:L") и т. д.

Проблемапроисходит из-за того, что в моей функции sKey является массивом, и если я пытаюсь использовать тот же подход, что и моя функция retValue (здесь, выше, в разделе , это работает: ), то происходит сбой, потому что теперь в retCoord, у меня есть 2 входа, и функция самоанализа, вызываемая ранее, не работает из-за второго входа.Конечно, я что-то упускаю, и всегда есть лучший и более элегантный способ решения проблемы.Но сейчас, может ли кто-нибудь помочь мне с этим?

EDIT2:

Я немного изменил код и, кажется, я продвинулся вперед, но пока не совсем.Проверьте комментарий ниже для строки, обозначенной (*):

function retCoord(sKey, sIRange) {
  var key = '';
  try {
    key = SpreadsheetApp.getActive().getRange(sKey).getValue();
    return key;
  }
  catch(e) {
    if (sKey.map) {
      var objKey = sKey.map(retCoord);
      return objKey; // (*) <--- comments below
      key = objKey;
    } else {
      key = sKey;
    }
  }
  var range = SpreadsheetApp.getActive().getRange(sIRange).getValues();
  nbRow = range.length;
  nbColumn = range[0].length;
  for(var i = 0; i<nbRow; i++){
    for(var j = 0; j<nbColumn; j++){
      if(range[i][j] == key){
        return key + " = "+ i + ", " + j;
      }
    }
  }
}

Эту (*) строку я добавил только, чтобы увидеть, что возвращалось с карты.Удивительно (в некотором смысле), это объект со всеми элементами этого столбца, и это ожидается.Чего я не ожидал, так это того, что если я верну этот объект в свою ячейку электронной таблицы, он вернет только значение этой конкретной ячейки (как я хотел, но не совсем так, как ожидалось).Но проблема в том, что я не могу использовать этот объект для сравнения со строкой, поскольку он будет расширяться и становиться чем-то другим и никогда не будет совпадать.Посмотрите:

  1. Если я сделаю return objKey в своей пользовательской функции, то через ячейку O1 он возвращает «a», в O2 он возвращает «b», в O3 он возвращает «c», как и ожидалось, потому что тезначения моих клеток D1, D2, D3 соответственно.
  2. Если я делаю return "-> " + objKeyв моей пользовательской функции вместо возврата -> a, -> b, -> c в O1, O2, O3 соответственно, он возвращает -> =A:A,a,b,c,d,e,f для всех ячеек в column O, что, кажется, имело какой-то тип objKey.toString() под капотом перед конкатенацией с "->"

Вывод: как "принудительно" привести видимый результат objKey в строку, сохраняя видимый результат при возврате объекта без его изменения?Проще говоря, я хочу, чтобы конкатенация «некоторая строка» + была равна «некоторой строке» + «одна строка, представляющая значение в этой строке вместо объекта».Другими словами, что, черт возьми, здесь происходит?Как Google Sheets теперь, когда в этой строке этот элемент представляет тот, который я хочу?Это то, что я спросил в «PS».в первой части этого поста.

1 Ответ

0 голосов
/ 25 сентября 2019

Вы хотите найти все ключи в столбце sKey в пределах диапазона sIRange и отметить положение каждой клавиши в диапазоне в соответствующей строке в столбце назначения?

Вот как это можно сделать с помощьюApps Script без формул:

function retCoord(sKeyColumn, destinationColumn, sIRange) {
  var key = sKeyColumn;
  var range=SpreadsheetApp.getActive().getRange(sIRange);
  var rangeValues = SpreadsheetApp.getActive().getRange(sIRange).getValues();
  var nbRow = rangeValues.length;
  var nbColumn = rangeValues[0].length;
  var sKeyRange=SpreadsheetApp.getActive().getRange(sKeyColumn);
  var destinationRange=SpreadsheetApp.getActive().getRange(destinationColumn);
  var sKeyValues=sKeyRange.getValues();
  for(var k=0;k<sKeyValues.length;k++){
    for(var i = 1; i<=nbRow; i++){
      for(var j = 1; j<=nbColumn; j++){
        if(range.getCell(i, j).getValue() == sKeyValues[k][0]){
          destinationRange.getCell(k+1, 1).setValue(range.getCell(i, j).getA1Notation());
        }
      }
    }
  }
}

Пример вызова:

function myFunction(){
retCoord('A1:A6','B1:B6','C1:J7');
}

retCoord('A:A','B:B','C:J'); также будет работать, но займет очень много времени, так как код также будет проходить по пустым строкам

...