Google Apps Script: Как эффективно фильтровать данные?

Что такое Google Apps Script и зачем он нужен для обработки данных?

Google Apps Script (GAS) — это облачный язык сценариев, основанный на JavaScript, который позволяет автоматизировать задачи в Google Workspace (Sheets, Docs, Slides, Forms, Gmail, Calendar и т.д.). В контексте обработки данных, GAS позволяет автоматизировать сбор, обработку, фильтрацию и анализ информации, хранящейся в таблицах Google (Google Sheets), а также интегрировать её с другими сервисами.

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

Обзор основных методов фильтрации данных в таблицах Google

В Google Apps Script для фильтрации данных в таблицах можно использовать несколько подходов:

Простые циклы for и условные операторы if: Подходят для базовой фильтрации и небольших объемов данных.

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

Встроенные функции таблиц: Некоторые функции таблиц, такие как createFilter() и sort(), можно использовать для фильтрации и сортировки данных непосредственно в таблице. Они оптимизированы для работы с большими объемами данных.

SQL-подобные запросы (через SpreadsheetApp.newDataSourceSpec()): Для более сложных сценариев, можно создавать запросы к данным таблицы, используя синтаксис, напоминающий SQL. Это может быть полезно, когда требуются агрегации, объединения или другие сложные операции.

Предварительная подготовка: получение доступа к данным таблицы

Прежде чем приступить к фильтрации данных, необходимо получить доступ к нужной таблице и диапазону данных. Вот пример кода:

/**
 * Получает доступ к таблице и диапазону данных.
 * @param {string} spreadsheetId ID таблицы.
 * @param {string} sheetName Название листа.
 * @param {string} rangeNotation Нотация диапазона (например, "A1:C10").
 * @return {Array<Array>} Двумерный массив данных.
 */
function getData(spreadsheetId, sheetName, rangeNotation) {
  // @ts-ignore
  const ss = SpreadsheetApp.openById(spreadsheetId);
  const sheet = ss.getSheetByName(sheetName);
  if (!sheet) {
    throw new Error(`Лист с именем ${sheetName} не найден.`);
  }
  const range = sheet.getRange(rangeNotation);
  const values = range.getValues();
  return values;
}

// Пример использования:
const spreadsheetId = "YOUR_SPREADSHEET_ID";
const sheetName = "Sheet1";
const rangeNotation = "A1:C100";
const data = getData(spreadsheetId, sheetName, rangeNotation);

Замените YOUR_SPREADSHEET_ID на фактический ID вашей таблицы.

Простые методы фильтрации данных

Фильтрация по одному критерию: точное соответствие

Этот метод предполагает поиск строк, где значение в определенном столбце точно соответствует заданному значению.

/**
 * Фильтрует данные по точному соответствию в указанном столбце.
 * @param {Array<Array>} data Двумерный массив данных.
 * @param {number} columnIndex Индекс столбца для фильтрации (начиная с 0).
 * @param {any} criteria Значение для точного соответствия.
 * @return {Array<Array>} Отфильтрованный массив данных.
 */
function filterByExactMatch(data, columnIndex, criteria) {
  const filteredData = [];
  for (let i = 0; i < data.length; i++) {
    if (data[i][columnIndex] === criteria) {
      filteredData.push(data[i]);
    }
  }
  return filteredData;
}

// Пример использования:
const columnIndex = 0; // Фильтруем по первому столбцу
const criteria = "apple";
const filteredData = filterByExactMatch(data, columnIndex, criteria);

Фильтрация по числовым значениям: больше, меньше, равно

Этот метод фильтрует строки на основе сравнения числовых значений в заданном столбце с заданным порогом.

/**
 * Фильтрует данные по числовому значению в указанном столбце.
 * @param {Array<Array>} data Двумерный массив данных.
 * @param {number} columnIndex Индекс столбца для фильтрации (начиная с 0).
 * @param {number} criteria Числовое значение для сравнения.
 * @param {string} operator Оператор сравнения (">", "=", "<=").
 * @return {Array<Array>} Отфильтрованный массив данных.
 */
function filterByNumber(data, columnIndex, criteria, operator) {
  const filteredData = [];
  for (let i = 0; i ':
          if (value > criteria) filteredData.push(data[i]);
          break;
        case '<':
          if (value =':
          if (value >= criteria) filteredData.push(data[i]);
          break;
        case '<=':
          if (value =";
const filteredData = filterByNumber(data, columnIndex, criteria, operator);

Использование `if` для базовой фильтрации строк

Простой способ фильтрации, который хорошо подходит для небольших объемов данных и простых критериев.

function basicRowFilter(data) {
  const filteredData = [];

  for (let i = 0; i < data.length; i++) {
    const row = data[i];

    // Пример: фильтрация строк, где первый элемент начинается с 'A'
    if (typeof row[0] === 'string' && row[0].startsWith('A')) {
      filteredData.push(row);
    }
  }

  return filteredData;
}

Продвинутая фильтрация данных

Фильтрация с использованием `filter()` и лямбда-выражений

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

/**
 * Фильтрует данные с использованием метода filter() и лямбда-выражения.
 * @param {Array<Array>} data Двумерный массив данных.
 * @param {function(Array): boolean} filterFunction Функция фильтрации, принимающая строку (массив) и возвращающая boolean.
 * @return {Array<Array>} Отфильтрованный массив данных.
 */
function filterWithLambda(data, filterFunction) {
  return data.filter(filterFunction);
}

// Пример использования: Фильтруем строки, где второй столбец > 50
const filteredData = filterWithLambda(data, row => typeof row[1] === 'number' && row[1] > 50);

Фильтрация по нескольким критериям: логические операторы `И` и `ИЛИ`

Для фильтрации по нескольким критериям используйте логические операторы && (И) и || (ИЛИ) внутри условия.

Реклама
/**
 * Фильтрует данные по нескольким критериям, используя логические операторы.
 * @param {Array<Array>} data Двумерный массив данных.
 * @return {Array<Array>} Отфильтрованный массив данных.
 */
function filterByMultipleCriteria(data) {
  return data.filter(row => {
    // Пример: Фильтруем строки, где первый столбец начинается с "A" И второй столбец > 50
    const condition1 = typeof row[0] === 'string' && row[0].startsWith("A");
    const condition2 = typeof row[1] === 'number' && row[1] > 50;
    return condition1 && condition2; // И
    // return condition1 || condition2; // ИЛИ
  });
}

// Пример использования:
const filteredData = filterByMultipleCriteria(data);

Фильтрация по частичному совпадению текста (поиск подстроки)

Для поиска подстроки в тексте используйте метод String.prototype.includes() или String.prototype.indexOf().

/**
 * Фильтрует данные по частичному совпадению текста в указанном столбце.
 * @param {Array<Array>} data Двумерный массив данных.
 * @param {number} columnIndex Индекс столбца для фильтрации (начиная с 0).
 * @param {string} searchText Текст для поиска.
 * @return {Array<Array>} Отфильтрованный массив данных.
 */
function filterByPartialMatch(data, columnIndex, searchText) {
  return data.filter(row => {
    const value = row[columnIndex];
    if (typeof value === 'string') {
      return value.toLowerCase().includes(searchText.toLowerCase()); // Игнорируем регистр
    }
    return false;
  });
}

// Пример использования:
const columnIndex = 0; // Фильтруем по первому столбцу
const searchText = "app";
const filteredData = filterByPartialMatch(data, columnIndex, searchText);

Оптимизация производительности фильтрации

Избегание циклов: использование встроенных функций таблиц

По возможности используйте встроенные функции Google Sheets, такие как QUERY или FILTER, вместо написания собственных циклов. Эти функции оптимизированы для работы с данными таблиц и могут значительно повысить производительность, особенно при работе с большими объемами данных.

Кэширование данных для ускорения повторной фильтрации

Если данные не изменяются часто, закэшируйте их в скрипте, чтобы избежать повторного чтения из таблицы при каждой фильтрации. Используйте глобальные переменные или Service Properties / User Properties для хранения закэшированных данных.

Использование массивов для повышения эффективности

Операции с массивами в JavaScript, как правило, быстрее, чем операции с ячейками в Google Sheets. Преобразуйте данные из таблицы в массив для фильтрации, а затем, при необходимости, запишите отфильтрованные данные обратно в таблицу.

Примеры и лучшие практики

Фильтрация списка задач по статусу (выполнено, в процессе, отложено)

Предположим, у вас есть таблица со списком задач, где один из столбцов содержит статус задачи (Выполнено, В процессе, Отложено). Вы можете отфильтровать список задач по определенному статусу:

/**
 * Фильтрует список задач по статусу.
 * @param {Array<Array>} tasksData Двумерный массив данных о задачах (столбцы: название, описание, статус).
 * @param {string} status Статус для фильтрации.
 * @return {Array<Array>} Отфильтрованный массив задач.
 */
function filterTasksByStatus(tasksData, status) {
  const statusColumnIndex = 2; // Предполагаем, что статус находится в третьем столбце (индекс 2)
  return tasksData.filter(task => task[statusColumnIndex] === status);
}

// Пример использования:
const tasksData = getData("YOUR_SPREADSHEET_ID", "Tasks", "A1:C100");
const completedTasks = filterTasksByStatus(tasksData, "Выполнено");

Фильтрация списка клиентов по региону и объему продаж

Предположим, у вас есть таблица со списком клиентов, где есть столбцы с регионом и объемом продаж. Вы можете отфильтровать клиентов по региону и объему продаж, например, найти всех клиентов из региона "Москва" с объемом продаж более 100000.

/**
 * Фильтрует список клиентов по региону и объему продаж.
 * @param {Array<Array>} clientsData Двумерный массив данных о клиентах (столбцы: регион, объем продаж).
 * @param {string} region Регион для фильтрации.
 * @param {number} salesThreshold Минимальный объем продаж.
 * @return {Array<Array>} Отфильтрованный массив клиентов.
 */
function filterClientsByRegionAndSales(clientsData, region, salesThreshold) {
  const regionColumnIndex = 0; // Предполагаем, что регион находится в первом столбце
  const salesColumnIndex = 1; // Предполагаем, что объем продаж находится во втором столбце
  return clientsData.filter(client => {
    return client[regionColumnIndex] === region && typeof client[salesColumnIndex] === 'number' && client[salesColumnIndex] > salesThreshold;
  });
}

// Пример использования:
const clientsData = getData("YOUR_SPREADSHEET_ID", "Clients", "A1:B100");
const filteredClients = filterClientsByRegionAndSales(clientsData, "Москва", 100000);

Обработка ошибок и исключений при фильтрации данных

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

/**
 * Фильтрует данные с обработкой ошибок.
 * @param {Array<Array>} data Двумерный массив данных.
 * @param {number} columnIndex Индекс столбца для фильтрации.
 * @param {string} searchText Текст для поиска.
 * @return {Array<Array>} Отфильтрованный массив данных или null в случае ошибки.
 */
function filterDataWithErrorHandler(data, columnIndex, searchText) {
  try {
    // Проверяем, что columnIndex находится в пределах допустимого диапазона
    if (columnIndex = data[0].length) {
      throw new Error(`Неверный индекс столбца: ${columnIndex}`);
    }

    return data.filter(row => {
      const value = row[columnIndex];
      if (typeof value === 'string') {
        return value.toLowerCase().includes(searchText.toLowerCase());
      } else {
        return false; // Возвращаем false для нестроковых значений
      }
    });
  } catch (error) {
    console.error("Ошибка при фильтрации данных:", error);
    return null; // Или можно выбросить ошибку снова: throw error;
  }
}

// Пример использования:
const columnIndex = 0;
const searchText = "app";
const filteredData = filterDataWithErrorHandler(data, columnIndex, searchText);

if (filteredData) {
  // Обрабатываем отфильтрованные данные
} else {
  // Обрабатываем ошибку
}

Добавить комментарий