Google возвращает лист ячеек из указанного диапазона


Так что сейчас у меня есть функция, которая вызывается в нескольких местах, в некоторых из моих таблиц Google. Сейчас он принимает Range объект, string для поиска и необязательный boolean чтобы определить, следует ли сделать поиск с учетом регистра или нет, и по умолчанию true.

function getCellsWithValueInRange(SearchRange, search_string, case_sensitive) {
    var case_sensitive = (case_sensitive !== undefined && case_sensitive === false) ? false : true;
    var result = [];
    var RangeValues = { values: SearchRange.getValues(),
                         width: SearchRange.getWidth(),
                        height: SearchRange.getHeight(),
                         start: { column: SearchRange.getColumn(),
                                     row: SearchRange.getRow() }};
    for (var x = 0; x < RangeValues.width; x++) {
        for (var y = 0; y < RangeValues.height; y++) {
            if (!case_sensitive) {
                // Lower case the search term and potential result, but ONLY if either terms have the toLowerCase method (like date objects).
                search_string = search_string.toLowerCase ? search_string.toLowerCase() : search_string;
                RangeValues.values[y][x] = RangeValues.values[y][x].toLowerCase ? RangeValues.values[y][x].toLowerCase() : RangeValues.values[y][x]; 
            }
        if (search_string === RangeValues.values[y][x]) {
            result.push(SearchRange.getCell(y + RangeValues.start.row, x + RangeValues.start.column));
        }
      }
    }
    return result;
}

Сейчас этот код работает, но я не очень доволен по нескольким причинам:

  • В нем используется несколько вложенных циклов, которые чувствуют себя и выглядят ужасно (отладка это была боль).
  • У меня есть сомнения в его производительности. Сейчас я пытался следовать лучшей практике по пакетирование извлечения (первый проект этого кода только напрямую ссылаться на конкретные Ranges через getCell в вложенных циклов, но выступление было настолько плохо, что любой диапазон, который был более 600 строк просто сдался, следовательно, использование getValues() вместо. Я еще не посмотрел выступление этой версии, но по крайней мере она будет принимать большие диапазоны (примерно 12 столбцов × 1300+ строк) не из-за превышения максимального времени выполнения.
  • Я понятия не имею, если есть какие-то параметры поиска, что бы вызвать эту функцию, чтобы потерпеть неудачу. Я имею в виду, это уже вызывает ошибку, если ячейки Range это object (т. е. когда это свидание). Где еще удастся? Я могу защитить себя от других экземпляров?

В любом случае, там лучше, maintanable и производительным способами получить этот код? Я бы согласился, что это не совсем будет самый быстрый код (он в буквальном смысле должен пройти любой вид диапазона, независимо от его состояния), но любой вид будет делать.

Я вроде заходил, в основном потому, что после поиска высоко и низко, я обнаружил, что это своего рода трудно, чтобы получить индексы для вложенных Arrays в JavaScript (и, следовательно, приложений Google скрипт), так что мои первоначальные попытки сделать это более функциональным с помощью map или filter (Я играл с помощью подчеркивания для Google приложений скрипт) просто ударил в кирпичную стену.



Комментарии
1 ответ

Я не запускать модульные тесты для этого на различных поисковых ресурсов, но она должна дать представление о том, как можно объединить индексной информации в результаты для употребления с различными методами класса. Потому что вы работаете в достаточно стабильной среде (Google Таблицы), вы можете быть уверены, что массив поиска, вы работаете с имеет гарантированный уровень вложенности (который ограничивает множество возможных вопросов).

Общая идея состоит в замене исходного значения с аннотированный объект, после чего можно удалить и структура столбца строки и работать только со значением. (Возможно, вы могли бы просто использовать reduce | forEach и push массив методов, позволяющих перейти от значений массива в двумерный массив аннотированных значения.)

function annotateAndCase_(input2DArr, lower) {
// Map the 0-base row and column indices onto the value.
return input2DArr.map(function (row, rowIndex) {
return row.map(function (val, colIndex) {
var v = (lower && typeof val.toLowerCase === 'function') ? val.toLowerCase() : val;
return {r: rowIndex, c: colIndex, v: v};
});
});
}

function getCellsWithValueInRange(SearchRange, search_string, case_sensitive) {
// Pass exactly `false` to disable case sensitivity. Other falsy (0, "", null, undefined) -> `true`
case_sensitive = case_sensitive !== false;
if (case_sensitive) {
search_string = search_string.toLowerCase();
}
const startRow = SearchRange.getRow(),
startCol = SearchRange.getColumn();

const indexedValues = annotateAndCase_(SearchRange.getValues(), !case_sensitive);

// 2D array with max nesting level = 1 -> https://stackoverflow.com/a/10865042
const flattened = Array.prototype.concat.apply([], indexedValues);

const results = flattened.filter(function (cell) {
return cell.v === search_string;
}).map(function (match) {
// Return a string R1C1 notation of each matched value.
return ["R", match.r + startRow, "C", match.c + startCol].join("");
});

// Use a RangeList to optimize obtaining a large number of possibly-disjoint ranges.
return results.length ? SearchRange.getSheet().getRangeList(results).getRanges() : [];
}

Как уже упоминалось в комментариях @Dimu, вы должны пересмотреть, зачем нужны отдельные ссылки на ячейки (возможно, просто в коллекцию в качестве RangeList достаточно, например, для лечения их в том же порядке).

Это также хорошая идея, чтобы отделить функциональные возможности аннотирования из этой специальной функции, которая ищет значения, поскольку это позволяет повторно использовать код, например аннотированный ряд объектов, использовать различные filter предикатов, различные преобразовательные mapС различным конечным потребителям, и так далее. Вероятно, далее необходимо отделить корпус с шагом аннотации - только определенные предикаты фильтр для аннотированного массива будет заботиться.

0
ответ дан 27 октября 2018 в 05:10 Источник Поделиться